问题
无法在函数内动态创建具有本地范围的类,但可以在顶层工作。
问题
如何在正确的命名空间范围内动态创建类。
我正在尝试动态创建添加到调用者命名空间的类。
这样我就可以做到以下几点。
import creator
creator.make('SomeClass')
print "SomeClass :", SomeClass
这可以在顶层添加动态类时工作,但是当试图在函数中做同样的事情时,这样创建的类只有本地范围,它不起作用。
我看到当放置在函数内部时有一些hack可以工作,但它会消失。
下面的代码显示的问题显然creator.py
比显示的要多。
# creator.py
import inspect
def make(classname):
t = type(classname, (object,), { })
frame = inspect.currentframe()
print "WILL make() - callers locals :", frame.f_back.f_locals.keys()
frame.f_back.f_locals[classname] = t
print "DID make() - callers locals :", frame.f_back.f_locals.keys()
return t
# example.py
import creator
print "WILL __main__ - locals :", locals().keys()
creator.make('SomeClass')
print "DID __main__ - locals :", locals().keys()
print "SomeClass :", SomeClass
print "-" * 80
def closed():
# This hack helps
# https://stackoverflow.com/a/1549221/1481060
# exec ''
class ClosedClass: pass
print "WILL closed() - locals :", locals().keys()
creator.make('AnotherClass')
print "DID closed() - locals :", locals().keys()
# NOT EXPECTED
try: print AnotherClass
except NameError, ex: print "OUCH:", ex
closed()
输出:
WILL __main__ - locals : ['creator', '__builtins__', '__file__', '__package__', '__name__', '__doc__']
WILL make() - callers locals : ['creator', '__builtins__', '__file__', '__package__', '__name__', '__doc__']
DID make() - callers locals : ['creator', '__builtins__', 'SomeClass', '__file__', '__package__', '__name__', '__doc__']
DID __main__ - locals : ['creator', '__builtins__', 'SomeClass', '__file__', '__package__', '__name__', '__doc__']
SomeClass : <class 'creator.SomeClass'>
--------------------------------------------------------------------------------
WILL closed() - locals : ['ClosedClass']
WILL make() - callers locals : ['ClosedClass']
DID make() - callers locals : ['ClosedClass', 'AnotherClass']
DID closed() - locals : ['ClosedClass', 'AnotherClass']
OUCH: global name 'AnotherClass' is not defined
我当然不想要OUCH:..
。
locals()
在一个内部看closed
会想象它应该可以工作,但正如 hack 中提到的那样,Python 编译器正在优化本地变量并且错过了新动态编译器的引入。
如果我取消注释该exec ''
行,那么它可以工作。
我可以创建具有全局范围的这些类,但我试图保持我的命名空间干净。
我当然可以,AnotherClass = creator.make('AnotherClass')
但我正在努力保持它DRY。
有没有办法让它在没有exec ''
黑客的情况下工作?
还是让它们全球化?