使用python with语句进行curry?

使用python with语句进行curry?,python,currying,with-statement,Python,Currying,With Statement,我不确定这是否是“良好的python实践”,但是否可以定义一个自定义文件对象,该对象可以执行以下操作: myfile = myopen('myfile.txt') with myfile: write('Hello World!') #notice we don't put "myfile.write(..)" here! @contextmanager def export(obj, *atts): yield [getattr(obj, a) for a in atts]

我不确定这是否是“良好的python实践”,但是否可以定义一个自定义文件对象,该对象可以执行以下操作:

myfile = myopen('myfile.txt')
with myfile:
    write('Hello World!') #notice we don't put "myfile.write(..)" here!
@contextmanager
def export(obj, *atts):
    yield [getattr(obj, a) for a in atts]
i、 e文件上下文创建了一个函数“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)

您可能认为需要修改
globals()
。但是,如果您在不同的模块中定义了上下文管理器,您将使用定义它的模块的全局变量。不是正在使用它的模块。因此,您需要在
\uuuuuu内置的
名称空间(内置函数所在的位置)中定义方法。这当然可以做到,但我觉得这是一个更糟糕的想法,特别是如果你想用它处理任意对象的话。可能是您以某种方式损坏了名称(例如,添加了一个前导下划线)。但即便如此,如果您将
嵌套在
语句中会怎么样


您希望Python的
with
语句与Pascal或VisualBasic语句类似,但这完全不是一回事。这就是说,拥有一个相当于Pascal/VB
with
语句的Python将是一件美好的事情;首先不能用
调用它,这根本不是一个好主意。显式比隐式好——通过显式地提到电路板,读者(几周后可能就是你!)可以立即知道正在操作哪个电路板。而且,没有必要。您可以通过其他方式使用更方便的语法:例如,使函数成为单个对象的方法。然后放下无意义的上下文管理器(它应该做什么?您已经事先创建了对象!)


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

这不是上下文管理器的目的,正如前面所说的,我反对“显式优于隐式”原则。让它工作的唯一方法是围绕Python的组合语义工作,这是它的优点之一。如果只有一个方法可以多次调用,则可以执行以下操作来保存键入:

move = ChessBoard().make_move
move("e4")
move("e5")
或使用多种此类方法:

board = ChessBoard()
move = board.make_move
give_up = board.give_up
# call methods
(在FP术语中,这实际上是部分应用,而不是套用。)

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

myfile = myopen('myfile.txt')
with myfile:
    write('Hello World!') #notice we don't put "myfile.write(..)" here!
@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
X类:
德福。。。
定义栏。。。
将导出(some_x,'foo','bar')作为(foo,bar):

foo()正如其他人所提到的,这可能是一个非常糟糕的主意,但我确实看到了一些有限的情况(可能是一种临时的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()

“我应该这样做吗?”-不。“我怎么能这样做?”-不可能。这个实现很糟糕,因为它破坏了上下文管理器的嵌套(并且不必要地弄乱了
全局的
——全局的
有什么问题?)。@delnan它糟糕的原因不止这些。我希望我的介绍性免责声明能够表明这种情况的使用范围非常狭窄,尽管我确实认为它对于单个模块、单一用途的应用程序或生成的代码可能很有用。我的意思是,假设我们想要这样做,那就太糟糕了。当然,一开始这样做可能不是个好主意,但如果我们正在这样做,我们可以而且应该比你提议的方式做得更好。请参阅我的答案,快速了解如何做得更好。@delnan我不同意你答案中描述的基本原理和方法。如果你不喜欢这个例子,我邀请你使用你的否决票的力量。我更感兴趣的是听你为什么不同意我建议的实现。因为它需要函数知道全局状态?