web-dev-qa-db-ja.com

Pythonのglobals()の理由は?

Pythonにglobals()関数がある理由は何ですか?グローバル変数の辞書のみを返します。グローバル変数はすでにグローバルであるため、どこでも使用できます。

def F():
    global x
    x = 1

def G():
    print(globals()["x"]) #will return value of global 'x', which is 1

def H():
    print(x) #will also return value of global 'x', which, also, is 1

F()
G()
H()

ここでポイントが本当に見えませんか?必要なのは、両方に同じ名前のローカル変数とグローバル変数がある場合だけでした

def F():
    global x
    x = 1

def G():
    x = 5
    print(x) #5
    print(globals()["x"]) #1

F()
G()

ただし、同じ名前の2つの変数があり、同じスコープ内で両方を使用する必要があるという問題に遭遇することはありません。

62
user1632861

Pythonは、実行環境を内省するための多数のツールをプログラマに提供します。 globals()はそれらの1つに過ぎず、デバッグセッションでグローバルスコープに実際に含まれているオブジェクトを確認するのに非常に役立ちます。

その背後にある理論的根拠は、locals()を使用して関数で定義された変数を表示したり、dirを使用してモジュールの内容を表示したりすることと同じです。オブジェクトの属性。

C++のバックグラウンドから来て、これらのことは不必要に思えます。静的にリンクされ、静的に型付けされた環境では、絶対にそうなります。その場合、コンパイル時に正確にどの変数がグローバルであるか、オブジェクトにどのメンバーが含まれるか、さらに別のコンパイル単位によってどの名前がエクスポートされるかがわかります。

ただし、動的言語では、これらは固定されていません。コードのインポート方法に応じて、または実行中に変更することもできます。そのため、少なくとも、デバッガでこの種の情報にアクセスできることは非常に貴重です。

81
Ian Clelland

関数の文字列名を使用して関数を呼び出す必要がある場合にも役立ちます。例えば:

def foo():
    pass

function_name_as_string = 'foo'

globals()[function_name_as_string]() # foo(). 
36
Alex Soroka

globals()およびlocals()の結果をevalexecfileおよび___import___コマンドに渡すことができます。そうすると、これらのコマンドが機能するための制限された環境が作成されます。

したがって、これらの関数は、現在のコンテキストとは潜在的に異なる環境が与えられることから恩恵を受ける他の関数をサポートするために存在します。たとえば、globals()を呼び出してから、これらの関数の1つを呼び出す前にいくつかの変数を削除または追加できます。

8
Bryan Oakley

globals()eval()に役立ちます-スコープ内の変数を参照するコードを評価したい場合、それらの変数はグローバルまたはローカルにあります。


少し拡張するために、eval()組み込み関数はPythonコードに与えられたコードの文字列を解釈します。署名はeval(codeString, globals, locals)です。次のように使用します:

_def foo():
    x = 2
    y = eval("x + 1", globals(), locals())
    print("y=" + y) # should be 3
_

これは、インタープリターが変数のlocals() dictからxの値を取得するため、機能します。もちろん、独自の変数辞書をevalに提供できます。

6
Richard Close

「宣言型python」で役立ちます。たとえば、以下のFooDefおよびBarDefは、一連のデータ構造を定義するために使用されるクラスであり、入力または構成として何らかのパッケージで使用されます。これにより、入力内容に大きな柔軟性がもたらされ、パーサーを作成する必要がなくなります。

_# FooDef, BarDef are classes

Foo_one = FooDef("This one", opt1 = False, valence = 3 )
Foo_two = FooDef("The other one", valence = 6, parent = Foo_one )

namelist = []
for i in range(6):
    namelist.append("nm%03d"%i)

Foo_other = FooDef("a third one", string_list = namelist )

Bar_thing = BarDef( (Foo_one, Foo_two), method = 'depth-first')
_

この構成ファイルは、ループを使用して_Foo_other_の構成の一部である名前のリストを作成することに注意してください。したがって、この構成言語には、使用可能なランタイムライブラリを備えた非常に強力な「プリプロセッサ」が付属しています。たとえば、構成を生成する一環として、複雑なログを検索したり、Zipファイルから物事を抽出してBase64でデコードしたりする場合(もちろん、このアプローチは、入力が信頼できないソース...)

パッケージは、次のようなものを使用して構成を読み取ります。

_conf_globals = {}  # make a namespace
# Give the config file the classes it needs
conf_globals['FooDef']= mypkgconfig.FooDef  # both of these are based ...
conf_globals['BarDef']= mypkgconfig.BarDef  # ... on .DefBase

fname = "user.conf"
try:
    exec open(fname) in conf_globals
except Exception:
    ...as needed...
# now find all the definitions in there
# (I'm assuming the names they are defined with are
# significant to interpreting the data; so they
# are stored under those keys here).

defs = {}
for nm,val in conf_globals.items():
    if isinstance(val,mypkgconfig.DefBase):
        defs[nm] = val
_

したがって、最終的にポイントに到達すると、globals()は、そのようなパッケージを使用するときに、一連の定義を手続き的に作成したい場合に便利です。

_for idx in range(20):
    varname = "Foo_%02d" % i
    globals()[varname]= FooDef("one of several", id_code = i+1, scale_ratio = 2**i)
_

これは書き出すことと同等です

_Foo_00 = FooDef("one of several", id_code = 1, scale_ratio=1)
Foo_01 = FooDef("one of several", id_code = 2, scale_ratio=2)
Foo_02 = FooDef("one of several", id_code = 3, scale_ratio=4)
... 17 more ...
_

pythonモジュールから定義の束を収集して入力を取得するパッケージの例は、PLY(Python-Lex-yacc) http://www.dabeaz.com/ply / -その場合、オブジェクトはほとんどが関数オブジェクトですが、関数オブジェクトのメタデータ(名前、docstring、定義の順序)も入力の一部を形成します。 of globals()。また、それは 'configuration'によってインポートされます-後者は通常のpythonスクリプト-他の方法ではなく)です。

作業したいくつかのプロジェクトで「宣言型python」を使用しましたが、それらの構成を作成するときにglobals()を使用する機会がありました。確かに、これは構成「言語」の設計方法の弱点によるものだと主張できます。この方法でglobals()を使用しても、明確な結果は得られません。ほぼ同一のステートメントを1ダース書くよりも、保守しやすい結果になります。

また、名前を使用して、構成ファイル内で変数に重要性を与えるために使用することもできます。

_# All variables above here starting with Foo_k_ are collected
# in Bar_klist
#
foo_k = [ v for k,v in globals().items() if k.startswith('Foo_k_')]
Bar_klist  = BarDef( foo_k , method = "kset")
_

このメソッドは、anypython多くのテーブルと構造を定義するモジュールで、より簡単にするために役立ちますデータにアイテムを追加します。参照も維持する必要はありません。

0
greggo

文字列からクラス 'classname'のインスタンスを取得するためにも使用できます。

class C:
    def __init__(self, x):
        self.x = x
        print('Added new instance, x:', self.x)


def call(str):
    obj = globals()[str](4)
    return obj

c = call('C')
print(c.x)
0
Bart