globals()、locals()、vars()の違いは何ですか?


146

どのような違いがあるglobals()locals()vars()?彼らは何を返しますか?結果の更新は役に立ちますか?


Python 3でこれらのいずれかを更新して、スクリプトを実際に機能させることはできますか?
チャーリーパーカー

回答:


172

これらはそれぞれ辞書を返します:

  • globals() 常にモジュール名前空間の辞書を返します
  • locals() 常に返すの辞書現在のネームスペースを
  • vars()リターンのいずれか、現在のネームスペースの辞書(引数なしで呼び出された場合)、または、引数の辞書。

localsそして、varsもう少し説明を使用できます。場合locals()関数の内部と呼ばれ、それが現在のローカル変数の名前空間の値(プラス任意のクロージャ変数)その瞬間のように戻り、それを持つ辞書を更新します。locals()同じスタックフレーム内で複数の呼び出しを行うと、毎回同じdictが返されf_localsます。属性としてスタックフレームオブジェクトにアタッチされます。辞書の内容は、各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()ローカル変数の正規表現としてdict を使用する、より古い、より遅い実行モードに切り替えます。

関数の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()単一のオブジェクトを引数として受け入れ、オブジェクトを指定すると、そのオブジェクトのが返さ__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__ローカル変数を格納することは意味がありません。再帰とマルチスレッドは、それぞれ独自のローカルを持つ関数への複数の呼び出しが同時に存在する可能性があるためです。

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__その中の任意のローカル変数を持っていません。


4
「ディクショナリへの割り当ては、実際のローカル名前空間には反映されません」という部分は、少し明確に表現されている場合があります。
スヴェンマルナッハ、

奇妙なことに、を使用すると、に追加された変数vars()またはlocals()関数内で呼び出された辞書にアクセスできますeval()。EG:が実行されるとdef test(): huh = locals(); huh['d'] = 4; print eval('d')4を出力しtest()ます!
Mark Mikofski、2013

1
実際にdict(によって返されるlocals())への割り当ては、たまたまローカルネームスペースに反映され、ローカルネームスペースへの変更は、たまたまdict(私のPythonで)に反映されます。唯一のことは、仕様がこの動作を保証しないことです。
2015

用語名のスコープの使用法は、名前空間よりも簡単に見えます
オーバーエクスチェンジ

1
@overexchange:import thisand googlesite:docs.python.org namespace
Ethan Furman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.