variable - python unittest global




関数内でのグローバル変数の使用 (12)

関数内でグローバル変数を作成または使用するにはどうすればよいですか?

ある関数でグローバル変数を作成すると、そのグローバル変数を別の関数でどのように使うことができますか? グローバル変数をアクセスする必要がある関数のローカル変数に格納する必要がありますか?


1つの関数でグローバル変数を作成すると、その変数を別の関数でどのように使用できますか?

以下の関数を使ってグローバルを作成することができます:

def create_global_variable():
    global global_variable # must declare it to be a global first
    # modifications are thus reflected on the module's global scope
    global_variable = 'Foo' 

関数を書くことは、実際にコードを実行することはありません。 したがって、 create_global_variable関数を呼び出します。

>>> create_global_variable()

変更を加えずにグローバルを使う

どのオブジェクトがポイントしているかを変更したくない限り、それを使うことができます:

例えば、

def use_global_variable():
    return global_variable + '!!!'

今度はグローバル変数を使うことができます:

>>> use_global_variable()
'Foo!!!'

関数内部からのグローバル変数の変更

別のオブジェクトでグローバル変数を指すには、グローバルキーワードを再度使用する必要があります。

def change_global_variable():
    global global_variable
    global_variable = 'Bar'

この関数を記述した後、実際にコードを変更したコードはまだ実行されていないことに注意してください。

>>> use_global_variable()
'Foo!!!'

だから関数を呼び出した後:

>>> change_global_variable()

グローバル変数が変更されていることがわかります。 global_variable名前が'Bar'指すようになりました。

>>> use_global_variable()
'Bar!!!'

Pythonの "global"は本当にグローバルではないことに注意してください。これはモジュールレベルでのみグローバルです。 したがって、それはグローバルであるモジュールで書かれた関数でのみ利用可能です。 関数は書き込まれたモジュールを覚えているので、他のモジュールにエクスポートされても、作成されたモジュールを調べてグローバル変数を検索します。

同じ名前のローカル変数

同じ名前のローカル変数を作成すると、グローバル変数を覆い隠します。

def use_local_with_same_name_as_global():
    # bad name for a local variable, though.
    global_variable = 'Baz' 
    return global_variable + '!!!'

>>> use_local_with_same_name_as_global()
'Baz!!!'

しかし、その誤った名前のローカル変数を使用しても、グローバル変数は変更されません。

>>> use_global_variable()
'Bar!!!'

あなたがしていることを正確に把握しておかなければ、グローバル変数と同じ名前のローカル変数を使わないでください。 私はまだそのような理由に遭遇していない。


Pythonは単純なヒューリスティックを使用して、ローカルとグローバルの間で変数をロードするスコープを決定します。 変数名が代入の左側に表示され、グローバル宣言されていない場合、変数名はローカルとみなされます。 割り当ての左側に表示されない場合は、グローバルであるとみなされます。

>>> import dis
>>> def foo():
...     global bar
...     baz = 5
...     print bar
...     print baz
...     print quux
... 
>>> dis.disassemble(foo.func_code)
  3           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (baz)

  4           6 LOAD_GLOBAL              0 (bar)
              9 PRINT_ITEM          
             10 PRINT_NEWLINE       

  5          11 LOAD_FAST                0 (baz)
             14 PRINT_ITEM          
             15 PRINT_NEWLINE       

  6          16 LOAD_GLOBAL              1 (quux)
             19 PRINT_ITEM          
             20 PRINT_NEWLINE       
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE        
>>> 

foo()代入の左側に表示されるbazが唯一のLOAD_FAST変数であることを見てください。


あなたが言っていることは、このようなメソッドを使うことです:

globvar = 5

def f():
    var = globvar
    print(var)

f()  # Prints 5

しかし、より良い方法は、このようなグローバル変数を使うことです:

globavar = 5
def f():
    global globvar
    print(globvar)
f()   #prints 5

どちらも同じ出力を与えます。


あなたの状況を正しく理解していれば、Pythonがローカル(関数)とグローバル(モジュール)名前空間をどのように扱うかがわかります。

次のようなモジュールがあるとします。

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

既に述べたように、 func1()に ' global '宣言を追加すると、 func2()は42を出力します。

def func1():
    global myGlobal
    myGlobal = 42

ここで起こっていることは、関数内のどこにでも割り当てられている名前は、明示的に指示されない限りその関数にとってローカルであると仮定していることです。 名前からの読み取りのみで、名前がローカルに存在しない場合は、スコープの名前(モジュールのグローバルスコープなど)の名前を検索しようとします。

したがって、 myGlobalという名前に42を割り当てると、Pythonは同じ名前のグローバル変数をシャドウするローカル変数を作成します。 そのローカルは範囲外になり、 func1()が返ってくるとgarbage-collectedます。 一方、 func2()は(変更されていない)グローバル名以外のものを見ることはできません。 このネームスペースの決定は、実行時ではなくコンパイル時に行われることに注意してください。もしfunc1()内のmyGlobalの値をそれに割り当てる前にUnboundLocalError取得するのでUnboundLocalError 、Pythonはすでにローカル変数ですが、それに関連する値はまだありません。 しかし、 ' global 'ステートメントを使うことで、Pythonはローカルに代入するのではなく、別の名前を探すべきだということをPythonに伝えます。

(この振る舞いは主にローカル名前空間の最適化によってもたらされたものだと考えています。この動作がなければ、PythonのVMは新しい名前が関数内に割り当てられるたびに少なくとも3回の名前検索を実行する必要がありますモジュール/組み込みレベルでは既に存在しています)、非常に一般的な操作が大幅に遅くなります。


グローバル配列の明示的な要素への書き込みには、グローバルな宣言が必要であるとは限りませんが、 "卸売り"への書き込みにはその要件があります。

import numpy as np

hostValue = 3.14159
hostArray = np.array([2., 3.])
hostMatrix = np.array([[1.0, 0.0],[ 0.0, 1.0]])

def func1():
    global hostValue    # mandatory, else local.
    hostValue = 2.0

def func2():
    global hostValue    # mandatory, else UnboundLocalError.
    hostValue += 1.0

def func3():
    global hostArray    # mandatory, else local.
    hostArray = np.array([14., 15.])

def func4():            # no need for globals
    hostArray[0] = 123.4

def func5():            # no need for globals
    hostArray[1] += 1.0

def func6():            # no need for globals
    hostMatrix[1][1] = 12.

def func7():            # no need for globals
    hostMatrix[0][0] += 0.33

func1()
print "After func1(), hostValue = ", hostValue
func2()
print "After func2(), hostValue = ", hostValue
func3()
print "After func3(), hostArray = ", hostArray
func4()
print "After func4(), hostArray = ", hostArray
func5()
print "After func5(), hostArray = ", hostArray
func6()
print "After func6(), hostMatrix = \n", hostMatrix
func7()
print "After func7(), hostMatrix = \n", hostMatrix

パラレル実行では、何が起こっているのか分からないと、グローバル変数が予期しない結果を引き起こす可能性があります。 次に、マルチプロセッシングでグローバル変数を使用する例を示します。 各プロセスは変数のコピーで動作することが明確に分かります。

import multiprocessing
import os
import random
import sys
import time

def worker(new_value):
    old_value = get_value()
    set_value(random.randint(1, 99))
    print('pid=[{pid}] '
          'old_value=[{old_value:2}] '
          'new_value=[{new_value:2}] '
          'get_value=[{get_value:2}]'.format(
          pid=str(os.getpid()),
          old_value=old_value,
          new_value=new_value,
          get_value=get_value()))

def get_value():
    global global_variable
    return global_variable

def set_value(new_value):
    global global_variable
    global_variable = new_value

global_variable = -1

print('before set_value(), get_value() = [%s]' % get_value())
set_value(new_value=-2)
print('after  set_value(), get_value() = [%s]' % get_value())

processPool = multiprocessing.Pool(processes=5)
processPool.map(func=worker, iterable=range(15))

出力:

before set_value(), get_value() = [-1]
after  set_value(), get_value() = [-2]
pid=[53970] old_value=[-2] new_value=[ 0] get_value=[23]
pid=[53971] old_value=[-2] new_value=[ 1] get_value=[42]
pid=[53970] old_value=[23] new_value=[ 4] get_value=[50]
pid=[53970] old_value=[50] new_value=[ 6] get_value=[14]
pid=[53971] old_value=[42] new_value=[ 5] get_value=[31]
pid=[53972] old_value=[-2] new_value=[ 2] get_value=[44]
pid=[53973] old_value=[-2] new_value=[ 3] get_value=[94]
pid=[53970] old_value=[14] new_value=[ 7] get_value=[21]
pid=[53971] old_value=[31] new_value=[ 8] get_value=[34]
pid=[53972] old_value=[44] new_value=[ 9] get_value=[59]
pid=[53973] old_value=[94] new_value=[10] get_value=[87]
pid=[53970] old_value=[21] new_value=[11] get_value=[21]
pid=[53971] old_value=[34] new_value=[12] get_value=[82]
pid=[53972] old_value=[59] new_value=[13] get_value=[ 4]
pid=[53973] old_value=[87] new_value=[14] get_value=[70]

同じ名前のローカル変数がある場合は、 globals()関数を使用しglobals()

globals()['your_global_var'] = 42

変更を表示するクラスの名前空間を参照してください。

この例では、runnerはファイルconfigからmaxを使用しています。 私はランナーがそれを使用しているときにmaxの値を変更するテストをしたい。

main / config.py

max = 15000

main / runner.py

from main import config
def check_threads():
    return max < thread_count 

tests / runner_test.py

from main import runner                # <----- 1. add file
from main.runner import check_threads
class RunnerTest(unittest):
   def test_threads(self):
       runner.max = 0                  # <----- 2. set global 
       check_threads()

既存の回答に加え、これをもっと混乱させるために:

Pythonでは、関数内でのみ参照される変数は暗黙的にグローバルです。 変数に関数本体のどこにでも新しい値が割り当てられていれば、それはローカルであるとみなされます。 関数内で変数に新しい値が割り当てられると、その変数は暗黙的にローカルなので、明示的に 'グローバル'として宣言する必要があります。

ちょっと驚くようなものですが、瞬時に考えればこれが説明されます。 一方では、割り当てられた変数にグローバルを必要とすることは、意図しない副作用を防ぐことができます。 一方、すべてのグローバル参照にグローバルが必要な場合は、常にグローバルを使用しています。 組み込み関数またはインポートされたモジュールのコンポーネントへのすべての参照をグローバルとして宣言する必要があります。 この混乱は、副作用を特定するためのグローバル宣言の有用性を打破するでしょう。

ソース: Pythonのローカル変数とグローバル変数のルールは何ですか?


私はこれを他の答えの中で見たことがないので、これを追加しています。誰かが似たようなことに苦労している人には役に立ちます。 globals()関数は、残りのコードに対してデータを「魔法のように」利用できるようにする可変グローバルシンボル辞書を返します。 例えば:

from pickle import load
def loaditem(name):
    with open(r"C:\pickle\file\location"+"\{}.dat".format(name), "rb") as openfile:
        globals()[name] = load(openfile)
    return True

そして

from pickle import dump
def dumpfile(name):
    with open(name+".dat", "wb") as outfile:
        dump(globals()[name], outfile)
    return True

変数をグローバル名前空間の外部にダンプ/ロードすることができます。 超便利で、マッスルではなく、大騒ぎではありません。 それはPython 3のみです。


続いて追加する場合は、ローカルで宣言されたすべてのグローバル変数をすべて含むファイルを使用し、次に 'import as'を使用します。

ファイルinitval.py

Stocksin = 300
Prices = []

ファイルgetstocks.py

import  initval as  iv

Def   getmystocks (): 
     iv.Stocksin  = getstockcount ()


Def getmycharts ():
    For ic in range (0,iv.Stocksin):

.....


関数内のグローバル変数を参照する場合は、 globalキーワードを使用してどの変数がグローバルであるかを宣言できます。 すべての場合に使用する必要はありません(ここで間違って主張する人物) - 式で参照されている名前が、この関数が定義されている関数のローカルスコープまたはスコープ内に見つからない場合、グローバル変数。

ただし、関数内でグローバルとして宣言されていない新しい変数に代入すると、暗黙的にローカルとして宣言され、同じ名前の既存のグローバル変数を覆い隠す可能性があります。

また、大域変数は、特にOOPが過剰である小規模なスクリプトの場合、そうでないと主張する一部のOOPの熱狂家に反して、有用である。





scope