Python2使用全局关键字和闭包注入模块范围

Python2使用全局关键字和闭包注入模块范围,python,scope,closures,inject,Python,Scope,Closures,Inject,tl;dr:是否可以将带有global关键字的函数以注入的global将关闭该模块的方式注入模块?(如何或为什么不?) 带示例的长版本 建议使用setattr方法注入模块名称空间: import foo ## before try: foo.bar() except AttributeError: print 'ok' # expected to print 'ok' ## magic def bar(): pass setattr(foo,'bar',bar)

tl;dr:是否可以将带有
global
关键字的函数以注入的
global
将关闭该模块的方式注入模块?(如何或为什么不?)


带示例的长版本

建议使用
setattr
方法注入模块名称空间:

import foo

## before
try:
    foo.bar()
except AttributeError:
    print 'ok'

# expected to print 'ok'

## magic
def bar():
    pass

setattr(foo,'bar',bar)

## after
foo.bar()
# expected to do nothing (instead of raising an error)
然而,这似乎并不像人们希望使用
global
关键字那样有效。例如:

## foo.py
a = 4
def bar():
    global a
    a = 5
def check(expectation):
    global a
    assert a == expectation, "%s == %s"%(a,expectation)
    a = 4

## rab.py
import foo
foo.bar()
# expected to return and it does
foo.check(5)
print 'bar: ok'
def rab():
    global a
    a = 6
setattr(foo,'rab',rab)
foo.rab()
# may be expected to return but it raises AssertionError:
foo.check(6)
print 'rab: ok' # never printed
foo.check
运行时,注入
rab
的方式是否可以使该
foo.a
变为
6
,同时保持原始
foo.check


是否可以将带有
global
关键字的函数以注入的
global
将关闭该模块的方式注入模块?(怎么做或为什么不?

这与您的想法不完全一样,但您可以:

def rab():
    foo.a = 6

foo.rab = rab  # No need to `setattr` in this simple example
foo.rab()
foo.check(6)
globals
将始终引用模块中定义函数的全局名称空间(无法更改此名称空间)1


1这确实是它唯一明智的行为方式——毕竟,没有什么可以阻止您将
rab
放入多模块名称空间。

rab的全局字典已经被加入。您可以在
rab.func\u globals
上看到它

该属性为只读,因此无法替换它

您可以在
foo
中创建一个新函数,并将代码从
rab
推送到其中:)

例如

但不要这样做

type(rab)(rab.func_code, foo.__dict__)
## rab.py
import foo
foo.bar()
# expected to return and it does
foo.check(5)
print 'bar: ok'
def rab():
    global a
    a = 6
foo.rab = type(rab)(rab.func_code, foo.__dict__)
foo.rab()
# may be expected to return but it raises AssertionError:
foo.check(6)
print 'rab: ok'