0

問題

関数内にローカルスコープを持つクラスを動的に作成することはできませんが、トップレベルで機能します。

質問

正しい名前空間スコープで動的にクラスを作成する方法。


呼び出し元の名前空間に追加されるクラスを動的に作成しようとしています。

私ができるように、次のことを行います。

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 ''ハックなしでそれを機能させる方法はありますか?

それとも、それらをグローバルにする場合ですか?

4

1 に答える 1

2

いいえ。ローカル変数にアクセスする唯一の方法は、locals()またはvars()を使用することです。どちらの場合も、ドキュメントには、戻り値の変更がローカル変数に影響を与えるという保証はないことが明記されていdictます。したがって、これを確実に行う方法はありません。

ローカルを静的に変更したい場合は、関数に関連付けられたコードオブジェクトを変更して、より多くのローカルを提供できますが、それが不可能である、確実に実行するのが非常に難しい場合があり、これを実行する理由はわかりません。

于 2013-03-06T19:59:43.730 に答える