web-dev-qa-db-ja.com

動的に設定されるローカル変数

Pythonでローカル変数をどのように動的に設定しますか?

(変数名は動的です)

PDATE:これは良い習慣ではないことを認識しており、発言は合法ですが、これは悪い質問ではなく、単なる理論的な質問です-なぜこれがわかりませんdownvotesを正当化します。

96
Jonathan

すでに投稿されている他の回答とは異なり、locals()を直接変更して、機能することを期待することはできません。

_>>> def foo():
    lcl = locals()
    lcl['xyz'] = 42
    print(xyz)


>>> foo()

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    foo()
  File "<pyshell#5>", line 4, in foo
    print(xyz)
NameError: global name 'xyz' is not defined
_

locals()の変更は未定義です。 locals()globals()が同じ場合、関数の外側で機能します。関数内では、通常は動作しません。

辞書を使用するか、オブジェクトに属性を設定します。

_d = {}
d['xyz'] = 42
print(d['xyz'])
_

または、必要に応じてクラスを使用します。

_class C: pass

obj = C()
setattr(obj, 'xyz', 42)
print(obj.xyz)
_

編集:関数ではない名前空間(モジュール、クラス定義、インスタンス)の変数へのアクセスは、通常辞書検索によって行われます(Svenがコメントで指摘しているように、たとえば、 ___slots___)を定義します。コンパイラは(通常)すべての名前を事前に知っているため、関数ローカルは速度を最適化できます。したがって、locals()を呼び出すまで辞書はありません。

Python locals()(関数内から呼び出される)のC実装では、ローカル変数の現在の値から初期化された通常の辞書を作成します。各関数内で任意の回数の呼び出しto locals()は同じ辞書を返しますが、locals()を呼び出すたびにローカル変数の現在の値でそれを更新します。これにより、辞書の要素への割り当ては無視(元々これがそうだと書いた)locals()から返された辞書内の既存のキーへの変更は、同じスコープでlocals()を次に呼び出すまでしか持続しない。

IronPythonでは、動作が少し異なります。内部でlocals()を呼び出す関数は、ローカル変数に辞書を使用するため、ローカル変数への割り当ては辞書を変更し、辞書への割り当ては変数を変更します[〜#〜] but [〜#〜 ]これは、その名前でlocals()を明示的に呼び出した場合のみです。 IronPythonのlocals関数に別の名前をバインドし、それを呼び出すと、名前がバインドされたスコープのローカル変数が得られ、それを介してローカル関数にアクセスする方法はありません。

_>>> def foo():
...     abc = 123
...     lcl = zzz()
...     lcl['abc'] = 456
...     deF = 789
...     print(abc)
...     print(zzz())
...     print(lcl)
...
>>> zzz =locals
>>> foo()
123
{'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456}
{'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456}
>>>
_

これはいつでも変更できます。唯一保証されているのは、locals()によって返される辞書への割り当ての結果に依存できないことです。

71
Duncan

他の人は、locals()に割り当てることを提案しています。これは、LOAD_FASTオペコードを使用してローカルにアクセスする関数内では機能しません。nless関数のどこかにexecステートメントがある場合。コンパイル時に不明な新しい変数を作成する可能性があるこのステートメントをサポートするために、Pythonは関数内の名前でローカル変数にアクセスすることを強制されるため、locals()execは、実行されるコードパスから外れている可能性があります。

def func(varname):
    locals()[varname] = 42
    return answer           # only works if we passed in "answer" for varname
    exec ""                 # never executed

func("answer")
>>> 42

注:これはPython 2.xでのみ機能します。Python 3、およびその他の実装(Jython、IronPythonなど)のこの愚かさはなくなりました。それをサポートしていないかもしれません。

ただし、これは悪い考えです。変数の名前がわからない場合、どのように変数にアクセスしますか?おそらくlocals()[xxx]。それでは、locals()を汚染するのではなく、独自の辞書を使用しないでください(そして、関数が実際に必要とする変数を上書きするチャンスをつかむ)。

24
kindall

(他の人への簡単なメモgooglin ')

それでは、locals()変更する方法ではありませんglobals()動作するはずです )を変更します。それまでの間、execになる可能性がありますが、非常に遅いため、正規表現と同様に、compile()最初に:

# var0 = 0; var1 = 1; var2 = 2
code_text = '\n'.join( "var%d = %d" % (n, n) for n in xrange(3) )

filename = ''
code_chunk = compile( code_text, filename, 'exec' )

# now later we can use exec:
exec code_chunk # executes in the current context
5
ジョージ

私は最後の時間を費やしました...数時間、私は、関数クロージャーの欠如をハックしようとして、私はこれを考え出しました、それは助けになるかもしれません:

common_data = ...stuff...
def process(record):
    ...logic...

def op():
    for fing in op.func_dict: # Key line number 1
        exec(fing + " = op.func_dict[fing]") # Key line number 2

    while common_data.still_recieving:
        with common_data._lock:
            if common_data.record_available:
                process(common_data.oldest_record)
        time.sleep(1.0)

op.func_dict.update(locals()) # Key line number 3
threading.Thread(target = op).start()

...

これはかなり重い/不自然な例ですが、地元の人が多い場合や、まだプロトタイプを作成している場合は、このパターンが役立ちます。ほとんどの場合、コールバックデリゲートなどを処理するために、すべてのデータストアがレプリケートまたは移動されることについて苦いだけでした。

3
Redsplinter

locals()を直接変更できます:

locals()['foo'] = 'bar'

しかし、より良い方法は、すべての動的変数名を辞書キーとして保持するいくつかの辞書を持つことです。

d = {}
for some in thing:
    d[some] = 'whatever'
2
poke

次の辞書があるとしましょう:

_DictionaryA = {'No Rating': ['Hobbit', 'Movie C', 'Movie G'],
               'Forget It': ['Avenger', 'Movie B'], 
               'Must See': ['Children of Men', 'Skyfall', 'Movie F'], 
               '3': ['X-Men', 'Movie D'],
               '2': ['Captain America', 'Movie E'], 
               '4': ['Transformers', 'Movie A']} 
_

以下のように新しい辞書を作成したい:

_NewDictionary1 = {'No Rating': ['Hobbit', 'Movie C', 'Movie G']} 
NewDictionary2 = {'Forget It': ['Avenger', 'Movie B']} 
NewDictionary3 = {'Must See': ['Children of Men', 'Skyfall', 'Movie F']}
_

ワンライナー:

_dics = [{k:v} for k,v in DictionaryA.iteritems()]
_

出力先は次のとおりです。

_[{'Must See': ['Children of Men', 'Skyfall', 'Movie F']}, {'Forget It': ['Avenger', 'Movie B']}, {'No Rating': ['Hobbit', 'Movie C', 'Movie G']}, {'3': ['X-Men', 'Movie D']}, {'2': ['Captain America', 'Movie E']}, {'4': ['Transformers', 'Movie A']}]
_

しかし、変数を正確に宣言するには、次のようにします。

_>>> i=0
>>> lcl = locals()
>>> for key,val in DictionaryA.iteritems():
        lcl["Dict" + str(i)] = {key:val}
        i += 1
_

ご覧のとおり、最初の3つのDict変数:

_>>> Dict0
{'Must See': ['Children of Men', 'Skyfall', 'Movie F']}
>>> Dict1
{'Forget It': ['Avenger', 'Movie B']}
>>> Dict2
{'No Rating': ['Hobbit', 'Movie C', 'Movie G']}
_

他の人が述べたように、関数に入れたい場合は、globals()に追加する必要があります:

_>>> glb = globals()
>>> for key,val in DictionaryA.iteritems():
        glb["Dict" + str(i)] = {key:val}
        i += 1
_
0
0x90

ローカル辞書を使用して、すべての動的バインディングをアイテムとして辞書に入れることができます。次に、そのような「動的変数」の名前がわかれば、その名前をキーとして使用して値を取得できます。

0
Adam Zalcman