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 的组合语义工作,这是它的强项之一。如果只有一个方法需要多次调用,你可以做些什么来节省打字:

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 的语句,但它根本不是一回事。也就是说,一个与 Pascal/VBwith语句等效的 Python 将是一件很可爱的事情。它只是不能被调用with

于 2012-11-03T15:55:21.627 回答
1

首先,这根本不是一个好主意。显式胜于隐式——通过明确提及板,读者(可能是几周后的你!)可以立即知道正在操作哪个板。此外,没有必要。您可以通过其他方式获得更方便的语法:例如,将函数设置为单个对象的方法。并删除无意义的上下文管理器(它应该做什么?您已经事先创建了一个对象!)。

为此,您需要全局状态,但不是globals特别需要。比如说,一个全局(确切地说是模块级)对象堆栈,上下文管理器推送和弹出对象,各个函数查看该堆栈的顶部。如果您知道自己的东西,实际上实施起来并不难,但正如我之前所说,没有理由这样做。

于 2012-11-03T15:57:28.637 回答
0

一种(至少半疯狂的)方法是这样的:

@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 回答