1. ホーム
  2. python

[解決済み] globals()、locals()、vars()の違いは何ですか?

2022-04-23 04:39:48

質問

とはどのような違いがあるのでしょうか? globals() , locals() および vars() ? これらは何を返すのでしょうか? 結果の更新は有用ですか?

解決方法は?

それぞれ辞書を返します。

  • globals() 常に の辞書を返します。 モジュール 名前空間
  • locals() 常に リターン a の辞書を作成します。 現在 名前空間
  • vars() リターン のどちらかです。 現在の名前空間の辞書 (引数なしで呼び出された場合) または その の辞書を使用します。

localsvars は、もう少し説明が必要でしょう。 もし locals() が関数内で呼ばれると、その時点のローカル変数の名前空間(とクロージャ変数)の値で dict を更新し、それを返します。複数回 locals() としてスタックフレームオブジェクトに添付されます。 f_locals 属性で指定します。dictの内容は、それぞれの locals() の呼び出しと、各 f_locals 属性へのアクセスですが のみ のような呼び出しや属性アクセス時に使用されます。変数が代入されたときに自動的に更新されることはなく、dict のエントリを代入しても、対応するローカル変数が代入されるわけではありません。

import inspect

def f():
    x = 1
    l = locals()
    print(l)
    locals()
    print(l)
    x = 2
    print(x, l['x'])
    l['x'] = 3
    print(x, l['x'])
    inspect.currentframe().f_locals
    print(x, l['x'])

f()

が与えてくれる。

{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2

最初の print(l) が表示されるだけです。 'x' エントリに割り当てられるためです。 l の後に発生します。 locals() を呼び出します。2番目の print(l) を呼び出した後 locals() を再度表示します。 l というエントリーがありますが、戻り値を保存していないにもかかわらず、このようになります。3番目と4番目の print は、変数を代入しても l にアクセスし、その逆も同様です。 f_locals にコピーされ、ローカル変数が locals() を再び使用します。

2つの注意点

  1. この動作は CPython 固有のものです -- 他の Python では、更新が自動的にローカルの名前空間に戻されるかもしれません。
  2. CPython 2.xでは、この機能を動作させるために exec "pass" の行を関数に追加します。これは関数を、より古い、より遅い実行モードで locals() ディクショナリーをローカル変数の標準的な表現として使用します。

もし locals() が呼び出されます。 外側 関数は、現在の名前空間である実際の辞書を返します。 名前空間へのさらなる変更 が辞書に反映され、辞書への変更は は名前空間に反映される。

class Test(object):
    a = 'one'
    b = 'two'
    huh = locals()
    c = 'three'
    huh['d'] = 'four'
    print huh

が与えてくれる。

{
  'a': 'one',
  'b': 'two',
  'c': 'three',
  'd': 'four',
  'huh': {...},
  '__module__': '__main__',
}

ここまでで、私が言ったことはすべて locals() にも当てはまります。 vars() ... ここで、その違いを説明します。 vars() は引数として1つのオブジェクトを受け付け、オブジェクトを渡すと、そのオブジェクトに対応する __dict__ を使用します。 典型的なオブジェクトの場合、その __dict__ は、その属性データのほとんどが格納される場所である。これには、クラス変数やモジュール・グローバルが含まれます。

class Test(object):
    a = 'one'
    b = 'two'
    def frobber(self):
        print self.c
t = Test()
huh = vars(t)
huh['c'] = 'three'
t.frobber()

となり、私たちに与えてくれます。

three

なお、関数の __dict__ はその属性の名前空間であり、ローカル変数ではありません。関数の __dict__ というのも、再帰処理やマルチスレッドにより、1つの関数が同時に複数回呼び出され、それぞれにローカル変数が設定されることがあるからです。

def f(outer):
    if outer:
        f(False)
        print('Outer call locals:', locals())
        print('f.__dict__:', f.__dict__)
    else:
        print('Inner call locals:', locals())
        print('f.__dict__:', f.__dict__)

f.x = 3

f(True)

となり、私たちに与えてくれます。

Inner call locals: {'outer': False}
f.__dict__: {'x': 3}
Outer call locals: {'outer': True}
f.__dict__: {'x': 3}

ここです。 f は自分自身を再帰的に呼び出すので、内側と外側の呼び出しは重なります。が呼び出されたとき、それぞれが自分のローカル変数を見る。 locals() しかし、両方の呼び出しで同じ f.__dict__f.__dict__ は、ローカル変数を持っていません。