如何在Python中静态(词法)绑定名称?

时间:2015-10-29 09:39:11

标签: python scope

考虑以下代码:

class Bar(object): pass

class Foo(object):
    def bar(self): return Bar()

f = Foo()
def Bar(): pass
print(f.bar())

打印None。但是那个可怜的家伙bar并不期望Bar成为后来的成就!

我的问题是,我可以在Foo(希望不会污染外部范围)内写出“最好”(最优雅,最有效,最恐怖,无论如何)的代码,这些代码将确保 bar可以引用声明时定义的Bar而不是调用?

(并不是我无法提出任何解决方案,而是因为我不知道正确的解决方案是什么。)

2 个答案:

答案 0 :(得分:2)

To"静态绑定"在创建函数/方法时的名称,您可以使用默认参数:

class Bar(object): 
    pass

class Foo(object):

    def bar(self, Bar=Bar): 
        return Bar()

this famous Python "gotcha",默认参数值仅评估一次。

在这种情况下,它并不是非常有用,因为将一个函数命名为一个类就是你自己的愚蠢错误(随后的错误会为你提供有用的信息);绑定名称只会使例如更难稍后嘲笑课程。但是,根据this question

解决嵌套函数中的后期绑定问题可能很有用

ShadowRanger's comment,如果你正在使用Python 3.x,你可以将*,添加到参数列表(bar(self, *, Bar=Bar)),以防止调用者意外地破坏默认值传递太多的位置论点;任何其他参数都会引发TypeError

答案 1 :(得分:0)

回答我自己的问题,但答案是将所有内容都放在封闭中:

def static_define(locals, super, tuple):  # All arguments are bound STATICALLY
    # Anything defined here will be exported externally
    class Foo(tuple):
        def __new__(cls, *args):
            return super(Foo, cls).__new__(cls, args)
    return locals()

# The following line "exports" all the returned locals into the current global namespace
(lambda f, bi: (lambda g: g.pop(f.__name__) and bi.None or g.update((lambda args: (lambda l: bi.reduce(lambda l, v: l.pop(v, bi.None) and bi.None or l, args, l))(f(*bi.map(lambda v: bi.eval(v, g), args))))(bi.__import__('inspect').getargspec(f).args)))(f.__globals__))(static_define, __builtins__)

super = None  # tamper!
print Foo()   # unaffected by tampering