8

Python 2.6.6 を使用していますが、デフォルトの Python 印刷機能をオーバーロードする必要があります。このコードは、組み込み関数を使用して出力を生成する必要があるシステムで使用される可能性があるため、実行する必要があります。そうしないと、出力が表示されません。

たとえば、次のような python スクリプトがあるとします。

from __future__ import print_function

def NewPrint(Str):
    with open("somefile.txt","a") as AFile:
        AFile.write(Str)

def OverloadPrint():
    global print
    print = NewPrint

OverloadPrint()
print("ha")

それは正常に動作します。「オーバーロードされた」印刷への入力は、NewPrint で指定されたファイルにあります。

それを念頭に置いて、上記の数行を実行し、スクリプトの実行全体で NewPrint が行うことを print で実行できるようにしたいと考えています。現在、print を使用する別のモジュールから関数を呼び出すと、上書きしたばかりではなく、組み込みの print が使用されます。これは名前空間と組み込みに関係があると思いますが、私の python は十分ではありません。

編集:

シンプルにしようとしましたが、これによりさらに混乱が生じたようです...

  1. print をオーバーロードする関数は GUI に出力するため、関数がオーバーロードされている場合はリダイレクトを気にする必要はありませ
  2. 私の例は、印刷機能が実際に行うことをしていないことを知っています。私がコーディングについてどのように考えているかのより良い例は次のとおりです(まだ素晴らしいとは言えません):

    def hli_print(*args, **kw):
        """
        print([object, ...], sep=' ', end='\n', file=sys.stdout)
        """
        sep = kw.get('sep', ' ')
        end = kw.get('end', '\n')
        File = kw.get('file', sys.stdout)
        args = [str(arg) for arg in args]
        string = sep.join(args) + end
        File.write(string)
        hli_Print(string)
    
  3. 上記の 2 から、GUI "hli_Print" に出力するために使用しなければならない関数を見ることができます。これは、swig ラッパーを通じて公開される C++ 関数です。

  4. 標準ライブラリと独自の swig ラッパーのみを使用し、開発者は print を関数として使用します (3.X に慣れるまで)。そのため、他のモジュールが print を呼び出して代わりに別のものを持っていることについて、あまり心配していませんでした。

すべてのコメントから、print() の代わりにいくつかの print_() 関数を使用するのが最善かもしれないと思います (これは現在私たちが行っていることです)。説明された。

4

2 に答える 2

15

@abarnertの回答といくつかのコメントが指摘しているように、置き換えるprintことはおそらく良い考えではありません。ただし、完全を期すために、コードが他のモジュールで正常にオーバーライドされなかった理由は次のとおりです。

print関数はモジュールで定義されています__builtin__builtinsPython 3では名前が変更されています)。Pythonインタープリターは、__builtin__モジュールの名前空間にあるすべてのものを、モジュール自体の名前空間にインポートせずに、実行中の他のすべてのコードで使用できるようにします。それは魔法です!

ただし、print(を使用してprint = NewPrint)という名前の独自の関数を作成しても、の元のバージョンは上書きされません__builtin__。モジュールの名前空間に、から古い変数をシャドウする新しい変数を作成しているだけです__builtin__。このglobalステートメントは、関数内の内部名前空間ではなく、モジュールのグローバル名前空間に書き込みたいことをPythonに通知するだけなので、役に立ちません。

デフォルトの関数を置き換えるには、モジュールprintで明示的に置き換える必要があります。__builtin__これを行うサンプルコードを次に示します。

from __future__ import print_function
try:
    import __builtin__ as builtins # Python 2
except ImportError:
    import builtins # Python 3

_print = print # keep a local copy of the original print
builtins.print = lambda *args, **kwargs: _print("foo:", *args, **kwargs)

繰り返しますが、これは本当に良い考えではありません。この回答で話していることを確実に理解しながら、Pythonが標準エラーに出力するために使用するパラメーターをprint受け入れないラムダ関数に置き換えることでPythonセッションの1つをクラッシュさせることができました。file数行後、別の例外のトレースバックを出力しようとしたときに2番目の例外が発生したときに、例外ハンドラーは満足しませんでした。

希望する結果を得るには、ほぼ間違いなくより良い方法があります。

于 2012-12-14T02:36:04.857 に答える
7

あなたの質問は意味がないと思います。

まず、Python 2.6 を実行している場合、インポートするものなどはすべてprint、独自のモジュールが関数を使用していてもステートメントを使用しprintます。したがって、関数をオーバーロードしても他には影響しません。

第二に、「このコードは、出力を生成するために組み込み関数を使用する必要があるシステムで使用される可能性があるため、実行する必要があります。そうしないと、出力が表示されません。」まあ、あなたNewPrintは組み込み関数ではないので、とにかく役に立ちません。

NewPrintまた、関数のほとんどの機能を実装していないことprintおよび実装しているビットでさえ、間違っていることにも注意してください(改行が続きます)。したがって、組み込み関数を独自のものに置き換えた場合、独自のコードと依存する stdlib/サードパーティ コードのほとんどが壊れてしまうだけです。print(s)s print

を置き換えるファイルのようなオブジェクトを作成することで、目的を達成できる場合がありますsys.stdout。そうでなければ、何がうまくいくかわかりません。例えば:

class FakeStdOut(object):
    # … lots of other stuff to implement or inherit
    def write(s):
        with open("somefile.txt", "a") as f:
            f.write(s)

def OverloadPrint():
    sys.stdout = FakeStdOut()

しかし、これが機能したとしても、それはおそらくあなたが本当に望んでいるものではありません. 欠陥のあるシェルを備えたプラットフォームでのクイック&ダーティスクリプトの場合、これは便利なアイデアです。しかし、そうでなければ、より良い解決策を思いつくよりも、長期的にはより多くの問題を引き起こす可能性があります. ここでは、うまくいかない可能性のあるいくつかのことを示します (完全なリストではなく、例としてのみ)。

  • 出力先のファイルを変更したい場合は、スクリプトを変更する必要があります。代わり>>にシェルで使用する場合は、スクリプトを別の方法で呼び出すことができます。
  • あなたのコードを読んだりデバッグしたりする人 (たとえば、あなたがその仕組みを忘れてから 3 か月後) は、何が起こっているのかに驚くでしょう。
  • 一部の stdlib/サードパーティ/同僚/など。呼び出すコードstdoutは、変更を行う前にそれが tty であることを確認し、インタラクティブな出力用に構成します。
  • リダイレクトする機会を得る前に一部のコードが出力され、問題を回避するために物事を並べ替える方法を見つけようとして何時間も費やすことになります。
  • 「ファイルのようなオブジェクト」を完全に実装する方法を知っている必要があり、その概念は 2.6 では完全に定義されていません。
  • どこかに、あなたが ing だと思っていたコードがいくつかありますがprint、実際には、たとえばlogging や書き込み、sys.stderrまたは何か他のことを行っていたので、すべてを に記録しているという誤った安心感を自分に与えてしまい、somefile.txt.顧客サイトで問題をデバッグするために欠落している情報がどうしても必要になる 6 か月後まで、他の方法を発見することはできません。

質問を編集したので、さらにいくつかの回答を次に示します。

すべてのコメントから、print() の代わりにいくつかの print_() 関数を使用していると思います

はい、それはより合理的なオプションです。しかし、私はおそらくそれを呼ばないでしょうprint_。そして、グローバル名の内外で実装を交換する代わりに、関数内に「するかしないか」のロジックを配置する方が簡単です (特に、コードがすべて含まれていない場合、ある時点でそれを台無しにするため) 1 つの大きなモジュール)。

私は同様のユース ケースのプロジェクトに取り組みました。syslog に移動したいメッセージがあり、開いている場合は GUI の「ログ ウィンドウ」にも移動しました。そこで、それをまとめた関数を書きましたが、代わりglogに書きたいと文句を言う人は誰もいませんでした。print(実際、チームの少なくとも 1 人はprint、特に GUI ロギング コードをデバッグする必要がある場合に、実際の出力に影響を与えることなく、デバッグ中に簡単な印刷に使用できることに非常に満足していました。)

loggingしかし、それは単に、新しい (当時の)モジュールの経験がなかったからです。logging Handler最近では、GUI ウィンドウに書き込む実装を作成し、そのハンドラーを追加するだけで、loggingどこでも標準メソッドを使用できると思います。そして、それがあなたにとって最良の選択肢かもしれません。

また、おそらく無関係な最後の 1 つの副次的な問題:

標準ライブラリと独自の swig ラッパーのみを使用し、開発者は print を関数として使用します (3.X に慣れるまで)。

では、そもそも 3.x を使用しないのはなぜでしょうか? 明らかに、3.x には実際の 3.x 標準ライブラリがあり、いくつかの__future__ステートメントを実行すると、3.x 標準ライブラリに近いものではなく、SWIG は 3.x で動作します…</p>

于 2012-12-14T00:36:57.370 に答える