3

これが「Python の優れた慣行」であるかどうかはわかりませんが、たとえば、次のようなカスタム ファイル オブジェクトを定義することは可能でしょうか。

myfile = myopen('myfile.txt')
with myfile:
    write('Hello World!') #notice we don't put "myfile.write(..)" here!

つまり、ファイル コンテキストは関数"write()" を作成するので、myfile.write(..) などを入力する必要はありません。これにより、入力の手間が省け、場合によっては目的が明確になります。例えば:

myboard = ChessBoard()
with ChessBoard():
    make_move("e4")
    make_move("e5")
    give_up()

とは対照的に

myboard = ChessBoard()
with ChessBoard():
    make_move("e4",board=myboard)
    make_move("e5",board=myboard)
    give_up(board=myboard)

問題は、これを行う必要があるかどうかです。どうすればそれを行うことができますか?どうにかして globals()-dict を変更する必要があると思いますが、それは悪い考えのようです..

編集:わかりましたありがとう!これをしないようにアドバイスする良い答えが複数ありました。だから私はそれをしません:o)

4

5 に答える 5

2

これはコンテキスト マネージャーの目的ではなく、既に述べたように、「明示的は暗黙的よりも優れている」という原則を打ち負かします。これを機能させる唯一の方法は、Python の強みの 1 つである合成セマンティクスを回避することです。複数回呼び出されるメソッドが 1 つしかない場合、入力を節約するためにできることは次のとおりです。

move = ChessBoard().make_move
move("e4")
move("e5")

または、複数のそのような方法で:

board = ChessBoard()
move = board.make_move
give_up = board.give_up
# call methods

(FP 用語では、これは実際には部分適用であり、カリー化ではありません。)

于 2012-11-03T16:08:45.213 に答える
1

を変更する必要があると思われますglobals()。ただし、使用しているモジュールとは別のモジュールでコンテキストマネージャーを定義した場合は、それが定義されたモジュールのグローバルを使用することになります。使用されていたモジュールではありません。__builtin__そのため、名前空間 (組み込み関数がある場所) でメソッドを定義する必要があります。これは確かに実行できますが、特に任意のオブジェクトで使用したい場合は、さらに悪い考えだと思います。おそらく、何らかの方法で名前を変更した場合 (たとえば、先頭にアンダースコアを追加するなど)。withしかし、その場合でも、ステートメントをネストするとどうなるでしょうか?

Python のwithステートメントが Pascal や Visual Basic のステートメントのようになることを期待していますが、まったく同じではありません。withそうは言っても、Pascal/VBステートメントに相当する Pythonがあれば、すばらしいものになるでしょう。呼び出すことができませんでしwithた。

于 2012-11-03T15:55:21.627 に答える
1

まず、これはまったく得策はありません。明示的は暗黙的よりも優れています。ボードについて明示的に言及することで、読者 (数週間後にあなたになるかもしれません!) は、どのボードが操作されているかを即座に知ることができます。また、必要ありません。他の方法でより便利な構文を使用できます。たとえば、個々のオブジェクトの関数メソッドを作成します。そして、無意味なコンテキスト マネージャーを削除します (何をすることになっているのでしょうか? 事前にオブジェクトを作成しています!)。

これを行うには、グローバル状態が必要ですが、具体的には必要ありませんglobals。たとえば、オブジェクトのグローバル (正確にはモジュール レベル) スタック、コンテキスト マネージャーがオブジェクトをプッシュおよびポップし、個々の関数がそのスタックの一番上を参照します。自分のことを知っていれば、実際に実装するのはそれほど難しくありませんが、前に言ったように、そうする理由はありません。

于 2012-11-03T15:57:28.637 に答える
0

それを行う1つの(少なくとも半分クレイジーな)方法は、次のようなものです。

@contextmanager
def export(obj, *atts):
    yield [getattr(obj, a) for a in atts]

その後:

class X:
   def foo...
   def bar...

with export(some_x, 'foo', 'bar') as (foo, bar):
      foo() <-- some_x.foo
      bar() <-- some_x.bar

もちろん、他の同様のソリューションと同様に、これは実生活ではまったく意味がありません。

于 2012-11-03T16:21:12.443 に答える
0

他の人が言及しているように、これはおそらく非常に悪い考えですが、私はそれが機能するかもしれないいくつかの限られたケース (おそらくその場しのぎの DSL として) を見ています。

class ChessBoard(object):
    def __init__(self, filename):
        self.filename = filename
    def __enter__(self):
        self.handle = open(self.filename, 'w')
        globals()['move'] = self.move
        globals()['give_up'] = self.give_up
    def __exit__(self, type, value, traceback):
        self.handle.close()
    def move(self, move):
        self.handle.write(move + '\n')
    def give_up(self):
        self.handle.write('resign' + '\n')

with ChessBoard('chess.txt'):
    move('e4')
    move('e5')
    give_up()
于 2012-11-03T16:27:19.357 に答える