简体   繁体   English

使用python with-statement进行currying?

[英]Currying using python with-statement?

I am not sure if this is 'good python practice', but would it be possible to, say, define a custom File-object that could do something like: 我不确定这是否是“好的python练习”,但是可以定义一个自定义的File-object,可以执行以下操作:

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

ie the File-context creates a function "write()" so that we don't have to type myfile.write(..) etc. It saves typing and makes the purpose clearer in some cases. 即文件上下文创建一个函数 “write()”,这样我们就不必输入myfile.write(..)等。它可以节省输入并在某些情况下使目的更清晰。 For instance: 例如:

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

as opposed to 而不是

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

The question is: should I do this? 问题是:我应该这样做吗? and HOW can I do it? 我该怎么做? I am guessing I would have to modify the globals()-dict somehow, but that seems like a bad idea.. 我猜我必须以某种方式修改globals() - dict,但这似乎是一个坏主意..

EDIT: Ok thanks! 编辑:好的,谢谢! I got multiple good answers advising me not to do this. 我得到了许多好的答案,建议我不要这样做。 So I won't do it :o) 所以我不会这样做:o)

This is not what context managers are for and, as has been remarked, I beats the "explicit is better than implicit" principle. 这不是上下文管理者的意思,正如已经说过的那样,我打败了“明确胜于隐性”的原则。 The only way to make it work would have to work around Python's compositional semantics, which are one of its strong points. 使其工作的唯一方法是必须解决Python的组合语义,这是它的优点之一。 What you can do to save typing, if there's only a single method to be called multiple times, is: 如果只有一种方法可以多次调用,那么你可以做些什么来节省输入:

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

Or with multiple such methods: 或者使用多种方法:

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

(In FP terms, this is actually partial application, not currying.) (在FP术语中,这实际上是部分应用,而不是currying。)

You'd think you'd need to modify globals() . 你认为你需要修改globals() But if you defined the context manager in a different module from the one you're using it in, you'd be using the globals of the module where it was defined. 但是如果您在与您正在使用的模块不同的模块中定义了上下文管理器,那么您将使用模块的全局变量来定义它。 Not the module where it was being used. 不是使用它的模块。 So you'd need to define the methods in the __builtin__ namespace (where the built-in functions are). 因此,您需要在__builtin__命名空间(内置函数所在的位置)中定义方法。 This can certainly be done, but it strikes me as an even worse idea, especially if you're wanting to use it with arbitrary objects. 这肯定可以做到,但它让我觉得更糟糕, 特别是如果你想用任意对象。 Maybe if you mangled the name in some way (eg, adding a leading underscore). 也许如果你以某种方式破坏了名称(例如,添加一个前导下划线)。 But even then, what if you nested the with statements? 但即便如此,如果嵌套with语句会怎么样?

You're looking for Python's with statement to be like Pascal's or Visual Basic's, and it's just not the same thing at all. 您正在寻找Python的with语句像帕斯卡或Visual Basic的,它只是不一样的东西都没有。 That said, a Python equivalent to the Pascal/VB with statement would be a lovely thing to have; 也就是说,一个等同于Pascal / VB with语句的Python将是一个可爱的东西; it just couldn't be called with . 它只是不能称其with

First off, this is not a good idea at all . 首先,这不是一个好主意。 Explicit is better than implicit -- by explicitly mentioning the board, the reader (which may be you in a few weeks!) can instantly tell which board is being operated on. 明确比隐含更好 - 通过明确提到董事会,读者(可能是你几个星期!)可以立即告诉哪个董事会正在进行操作。 Also, there is no need. 此外,没有必要。 You can have more convenient syntax in other ways: For example, make the functions methods of the individual objects. 您可以通过其他方式获得更方便的语法:例如,创建单个对象的函数方法。 And drop the pointless context manager (what's it supposed to do? You already create an object beforehand!). 并删除无意义的上下文管理器(它应该做什么?你已经预先创建了一个对象!)。

To do this, you'd need global state, but not globals specifically. 要做到这一点,你需要全局状态,但不是globals明确。 Say, a global (module-level to be exact) stack of objects, the context manager pushes and pops the object, and the individual functions look at the top of that stack. 比如,一个全局(模块级别准确)对象堆栈,上下文管理器推送和弹出对象,各个函数查看该堆栈的顶部。 It actually wouldn't be too hard to implement if you know your stuff, but as I said before, there is no reason to. 如果你知道你的东西,它实际上并不难实现,但正如我之前所说,没有理由。

One (at least half-crazy) way of doing that would be something like: 一种(至少半疯狂)的方式是这样的:

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

and then: 然后:

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

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

Of course, like any other similar solution this makes zero sense in real life. 当然,像任何其他类似的解决方案一样,这在现实生活中毫无意义。

As others have mentioned, this is probably a very bad idea, but I do see some limited cases (perhaps as a make-shift DSL) where it might be workable. 正如其他人所提到的,这可能是一个非常糟糕的主意,但我确实看到了一些有限的案例(可能是一个转移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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM