問題
関数内にローカルスコープを持つクラスを動的に作成することはできませんが、トップレベルで機能します。
質問
正しい名前空間スコープで動的にクラスを作成する方法。
呼び出し元の名前空間に追加されるクラスを動的に作成しようとしています。
私ができるように、次のことを行います。
import creator
creator.make('SomeClass')
print "SomeClass :", SomeClass
これは、最上位に動的クラスを追加するときに機能させることができますが、関数内で同じことを行おうとすると、作成されたクラスにローカルスコープしかないため、機能しません。
関数内に配置すると機能するハックがあるのを見ましたが、それは消えていくでしょう。
次のコードは、明らかに、示されている以上の問題があること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
それは機能するはずですが、ハックで述べたように、Pythonコンパイラはローカルを最適化しており、新しい動的なものの導入を見逃しています。
行のコメントを外すと、exec ''
機能します。
グローバルスコープでこれらのクラスを作成することはできますが、名前空間をクリーンに保とうとしています。
もちろんできますAnotherClass = creator.make('AnotherClass')
が、それを維持しようとしていDRYます。
exec ''
ハックなしでそれを機能させる方法はありますか?
それとも、それらをグローバルにする場合ですか?