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

如何在Python中静态(词汇)绑定名称?,python,scope,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(希望不会污染范围外)内部编写的“最佳”(最优雅、最高效、最具Pythonic的)代码是什么,它将确保bar能够引用在声明时定义的bar (不是我不能想出任

考虑以下代码:

class Bar(object): pass

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

f = Foo()
def Bar(): pass
print(f.bar())
它打印
None
。但是可怜的家伙
bar
没想到
bar
会变成后来的样子

我的问题是,我能在
Foo
(希望不会污染范围外)内部编写的“最佳”(最优雅、最高效、最具Pythonic的)代码是什么,它将确保
bar
能够引用在声明时定义的
bar

(不是我不能想出任何解决方案,而是我不知道正确的解决方案是什么。)

要在创建函数/方法时“静态绑定”名称,可以使用默认参数:

class Bar(object): 
    pass

class Foo(object):

    def bar(self, Bar=Bar): 
        return Bar()
根据,默认参数值只计算一次

在这种情况下,它不是非常有用,因为将函数命名为与类相同是您自己的愚蠢错误(随后的错误为您提供了有用的信息);绑定名称只会增加以后模拟类的难度。但是,根据,解决嵌套函数中后期绑定的问题可能会很有用



根据,如果您使用的是Python3.x,则可以将
*,
添加到参数列表(
bar(self,*,bar=bar)
)中,以防止调用方通过传递过多的位置参数意外地重击默认值;任何附加参数都会引发一个
类型错误

来回答我自己的问题,但答案是将一切都结束:

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

快速的想法是在
Foo
中声明您的
Bar
类,这样您的
Bar
就不会被外部代码污染scope@Anzel:假设已声明
Bar
,而不是我正在声明的内容。(我意识到我可以创建一个类变量来引用它,但我不知道这是否是最好的解决方案。)好的,我同意你的观点,我也希望看到一个干净的解决方案,考虑到动态性…这在什么方面真的是一个实际问题?此示例的行为方式与此示例相同,因为您正在替换
Foo
范围内的
Bar
。实际上,在编写Python模块/脚本/文件时,这种情况永远不会发生。也就是说,如果您在另一个模块中导入了
Foo
,那么无论该模块中有多少
Bar
标识符,
Foo
将始终引用其自身模块中的
Bar
。如果您要追溯更改自己完全控制的文件中的
Bar
,那就是您的问题。只需不这样做。遵循PEP8:函数具有小写字母和下划线名称:
def bar():pass
。在Python3中,通过只使用“statically-bound”arguments关键字,可以使此解决方案稍微更加健壮,这样人们就不会意外地用太多的位置参数来替换“real”函数原型。您只是咕哝了一声未命名的位置变量:
defbar(self,*,bar=bar):
“如果您更喜欢
TypeError
”-传递太多的参数已经给您带来了
TypeError
。你是说“如果你想自定义
类型错误
”还是什么
Foo().bar(1)
->
TypeError:bar()接受1个位置参数,但给出了2个
*args
方法也可以在Py2上工作,不像普通的
*
方法,但正如您所注意的,这意味着您必须执行所述的手动检查,其中
*
仅为Py3,但对您有效。@ShadowRanger没有,只是误解了裸
*
的功能!非常感谢。我倾向于写2.x和3.x兼容的代码,所以这对我来说是新的。可能是我的错,我把它描述成“咕噜咕噜咕噜的无名位置变量”;我在句法上是这么想的,但因为它们没有命名,所以在语义上它与命名的情况不同;如果没有名字的话,它不会发出嘶嘶声。@ShadowRanger是的,它不会发出嘶嘶声,而是会噎住它们!