【发布时间】:2013-03-06 19:46:38
【问题描述】:
问题
无法在函数内动态创建具有本地范围的类,但可以在顶层工作。
问题
如何在正确的命名空间范围内动态创建类。
我正在尝试动态创建添加到调用者命名空间的类。
以便我能够执行以下操作。
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:..。
在closed 中查看locals() 可以想象它应该可以工作,但正如黑客中提到的那样,Python 编译器正在优化本地变量并且错过了新动态编译器的引入。
如果我取消注释 exec '' 行,那么它可以工作。
我可以创建具有全局范围的这些类,但我试图保持我的命名空间干净。
我当然可以使用AnotherClass = creator.make('AnotherClass'),但我正在努力保持它DRY。
有没有办法让它在没有exec '' hack 的情况下工作?
还是让它们全球化?
【问题讨论】:
标签: python