20

localsローカル値の辞書を返す組み込み関数です。ドキュメントには次のように記載されています。

警告

このディクショナリの内容は変更しないでください。変更は、インタープリターによって使用されるローカル変数の値に影響しない場合があります。

残念ながら、Python 3.0 の exec にも同じ問題があります。これを回避する方法はありますか?

使用事例

検討:

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

depends は、引数で指定された文字列を list に格納しますtest.dependences。これらの文字列は辞書のキーdです。put_into_locals値を取り出しdてローカルに入れることができるように書きたいと思います。これは可能ですか?

4

5 に答える 5

17

exec をテストしたところ、Python 2.6.2 で動作します

>>> def test():
...     exec "a = 5"
...     print a
...
>>> test()
5

Python 3.x を使用している場合、辞書を使用するのではなく、実行時にローカルが配列として最適化されるため、これは機能しなくなります。

Python が「exec ステートメント」を検出すると、Python はローカル ストレージを配列からディクショナリに強制的に切り替えます。ただし、「exec」は Python 3.x の関数であるため、ユーザーが「exec = 123」のようなことを行った可能性があるため、コンパイラはこの区別を行うことができません。

http://bugs.python.org/issue4831

その場で関数のローカルを変更することは、いくつかの結果なしには不可能です: 通常、関数のローカルは辞書には格納されませんが、インデックスはコンパイル時に既知のロケールから決定される配列に格納されます。これは、少なくとも exec によって追加された新しいローカルと衝突します。古い exec ステートメントはこれを回避していました。コンパイラは、グローバル/ローカル引数のない exec が関数で発生した場合、その名前空間が「最適化されていない」、つまり locals 配列を使用しないことを知っていたからです。exec() は現在、通常の関数であるため、コンパイラは "exec" が何にバインドされている可能性があるかを認識していないため、特別に処理することはできません。

于 2009-09-20T05:09:33.320 に答える
8

ローカル変数は代入ステートメントによって変更されます。

文字列の辞書キーがある場合は、それらもローカル変数にしないでください。辞書キーとして使用してください。

絶対 にローカル変数が必要な場合は、これを行ってください。

def aFunction( a, b, c, d, e, f ):
    # use a, b, c, d, e and f as local variables

aFunction( **someDictWithKeys_a_b_c_d_e_f )

これにより、魔法のようなことをせずに、辞書からいくつかのローカル変数が取り込まれます。

于 2009-09-20T11:50:01.723 に答える
6

これは不可能です。これは、後でパフォーマンスを最適化できるようにするためだと思います。Python バイトコードはローカルを名前ではなくインデックスで参照します。locals() が書き込み可能である必要がある場合、インタープリターがいくつかの最適化を実装するのを妨げたり、それらをより困難にしたりする可能性があります。

このようなローカルを編集できることを保証するコア API を見つけることはできないと確信しています。なぜなら、その API がそれを行うことができれば、 locals() にもこの制限がないからです。

コンパイル時にすべてのローカルが存在する必要があることを忘れないでください。コンパイル時にローカルにバインドされていない名前を参照すると、コンパイラはそれがグローバルであると見なします。コンパイル後にローカルを「作成」することはできません。

考えられる解決策の 1 つについては、この質問を参照してください。

サンプル コードには基本的な問題があることに注意してください。

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

"test.dependencies"fが現在の関数である「f.dependencies」を参照していません。実際のグローバル値「test」を参照しています。つまり、複数のデコレータを使用する場合:

@memoize
@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

「test」は memoize のラップされた関数であり、依存する関数ではないため、機能しなくなります。Pythonには、「現在実行中の関数」(およびクラス) を参照する方法が本当に必要です。

于 2009-09-20T04:37:28.487 に答える
2

私はそれを変数に格納します:

refs    = locals()
def set_pets():
    global refs
    animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
    for i in range(len(animals)):
        refs['pet_0%s' % i] = animals[i]

set_pets()
refs['pet_05']='bird'
print(pet_00, pet_02, pet_04, pet_01, pet_03, pet_05 )
>> dog fish monkey cat fox bird

locals() に入れる前に dict をテストしたい場合:

def set_pets():
    global refs
    sandbox = {}
    animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
    for i in range(len(animals)):
        sandbox['pet_0%s' % i] = animals[i]
    # Test sandboxed dict here
    refs.update( sandbox )

MacOS Sierra 上の Python 3.6.1

于 2017-07-18T20:52:01.107 に答える
0

同じ制限が適用されるかどうかはわかりませんが、inspect モジュールを介して現在のフレーム (およびそこからローカル変数辞書) への直接参照を取得できます。

>>> import inspect
>>> inspect.currentframe().f_locals['foo'] = 'bar'
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect']
>>> foo
'bar'
于 2009-09-20T04:13:58.893 に答える