0

问题

无法在函数内动态创建具有本地范围的类,但可以在顶层工作。

问题

如何在正确的命名空间范围内动态创建类。


我正在尝试动态创建添加到调用者命名空间的类。

这样我就可以做到以下几点。

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 ''黑客的情况下工作?

还是让它们全球化?

4

1 回答 1

2

没有。访问局部变量的唯一locals()方法是通过orvars()并且在这两种情况下,文档都明确指出不能保证对dict返回的修改会影响局部变量,因此:没有办法可靠地做到这一点。

如果您想静态地修改局部变量,那么也许您可以修改与函数关联的代码对象以提供更多局部变量,但这可能是不可能的,或者很难可靠地做到这一点,我认为没有理由这样做。

于 2013-03-06T19:59:43.730 回答