tl; dr :是否可以将一个带有global
关键字的函数注入到模块中,注入的global
将关闭该模块? (怎么或为什么不?)
带示例的长版
在Runtime injection of attributes into module namespace中建议注入模块的命名空间,可以使用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
是否可以在rab
运行foo.a
时6
注入foo.check
,同时保留原始foo.check
?
是否可以以注入的global
将在该模块上关闭的方式向模块注入具有global
关键字的函数? (怎么或为什么不?)
答案 0 :(得分:3)
rab
的全球词典已经出炉。您可以在rab.func_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'
但不要这样做
答案 1 :(得分:0)
并非完全按照您考虑的方式,但您可以这样做:
def rab():
foo.a = 6
foo.rab = rab # No need to `setattr` in this simple example
foo.rab()
foo.check(6)
globals
总是引用函数定义的模块中的全局命名空间(没有办法改变这个)< SUP> 1 。
1 这实际上是它表现出来的唯一合理方式 - 毕竟,没有什么能阻止你将rab
放入多个模块名称空间。功能