Używanie zmiennych globalnych w funkcji


3112

Jak mogę utworzyć lub użyć zmiennej globalnej w funkcji?

Jeśli utworzę zmienną globalną w jednej funkcji, jak mogę użyć tej zmiennej globalnej w innej funkcji? Czy muszę przechowywać zmienną globalną w zmiennej lokalnej funkcji, która potrzebuje jej dostępu?

Odpowiedzi:


4243

Możesz użyć zmiennej globalnej w innych funkcjach, deklarując ją jak globalw każdej funkcji, która do niej przypisuje:

globvar = 0

def set_globvar_to_one():
    global globvar    # Needed to modify global copy of globvar
    globvar = 1

def print_globvar():
    print(globvar)     # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar()       # Prints 1

Wyobrażam sobie, że powodem tego jest to, że ponieważ zmienne globalne są tak niebezpieczne, Python chce się upewnić, że naprawdę wiesz, z czym się bawisz, wyraźnie wymagając globalsłowa kluczowego.

Zobacz inne odpowiedzi, jeśli chcesz udostępnić zmienną globalną między modułami.


838
Skrajną przesadą jest określanie globali jako „tak niebezpiecznych”. Globale są doskonale w każdym języku, który kiedykolwiek istniał i zawsze będzie istniał. Mają swoje miejsce. Powinieneś powiedzieć, że mogą powodować problemy, jeśli nie masz pojęcia, jak programować.
Anthony

207
Myślę, że są dość niebezpieczne. Jednak w Pythonie zmienne „globalne” są w rzeczywistości na poziomie modułu, co rozwiązuje wiele problemów.
Fábio Santos

246
Nie zgadzam się, że powodem, dla którego Python wymaga tego globalsłowa kluczowego, jest to, że globały są niebezpieczne. Raczej dlatego, że język nie wymaga jawnego deklarowania zmiennych i automatycznie zakłada, że ​​przypisywana zmienna ma zakres funkcji, chyba że powiesz jej inaczej. Słowo globalkluczowe jest środkiem zapewniającym, że jest inaczej.
Nate CK

7
@avgvstvs: A jeśli wdrażasz ten sam program bez globałów, nadal masz tę samą liczbę ścieżek kodu. Argument, który przedstawiłeś, nie jest przeciwko globałom.
Wyścigi lekkości na orbicie

13
@LightnessRacesinOrbit Nie rozumiem o co ci chodzi. Jeśli usuniesz zmienną globalną, usuniesz czynnik komplikujący to, że teraz dowolne funkcje nie mogą już zmieniać stanu programu w różnych punktach wykonania - zmieniając w ten sposób wykonanie w sposób, który w przeciwnym razie byłby niezauważalny dla innych funkcji opartych na tej zmiennej. Nie musisz już śledzić: „Czy f2()zmienił stan, więc teraz f3()może zrobić coś nieoczekiwanego? Funkcje mogą teraz działać niezależnie od stanu programu zewnętrznego.
avgvstvs

775

Jeśli dobrze rozumiem twoją sytuację, to, co widzisz, jest wynikiem tego, jak Python obsługuje lokalne (funkcyjne) i globalne (modułowe) przestrzenie nazw.

Powiedz, że masz taki moduł:

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

Możesz spodziewać się, że to wydrukuje 42, ale zamiast tego wydrukuje 5. Jak już wspomniano, jeśli dodasz globaldeklarację „ ” func1(), func2()wydrukuje 42.

def func1():
    global myGlobal
    myGlobal = 42

To, co się tutaj dzieje, polega na tym, że Python zakłada, że ​​każda nazwa przypisana w dowolnym miejscu funkcji jest lokalna dla tej funkcji, chyba że wyraźnie zaznaczono inaczej. Jeśli czyta tylko z nazwy, a nazwa nie istnieje lokalnie, spróbuje wyszukać nazwę w dowolnym zawierającym zakresie (np. Globalnym zasięgu modułu).

myGlobalDlatego po przypisaniu 42 do nazwy Python tworzy zmienną lokalną, która przesłania zmienną globalną o tej samej nazwie. Ten lokalny wykracza poza zakres i jest zwracany w śmieciach po func1()powrocie; tymczasem func2()nigdy nie widzi niczego poza (niezmodyfikowaną) nazwą globalną. Zauważ, że decyzja o przestrzeni nazw ma miejsce w czasie kompilacji, a nie w czasie wykonywania - jeśli miałbyś odczytać wartość myGlobalinside func1()przed przypisaniem do niej, dostałbyś UnboundLocalError, ponieważ Python już zdecydował, że musi to być zmienna lokalna, ale nie ma jeszcze żadnej wartości z tym związanej. Ale używając instrukcji „ global”, mówisz Pythonowi, że powinien szukać innej nazwy zamiast przypisywać ją lokalnie.

(Uważam, że takie zachowanie powstało głównie dzięki optymalizacji lokalnych przestrzeni nazw - bez tego zachowania maszyna wirtualna Pythona musiałaby wykonywać co najmniej trzy wyszukiwania nazw za każdym razem, gdy nowa funkcja jest przypisywana do funkcji (aby upewnić się, że nazwa nie już istnieją na poziomie modułu / wbudowanego), co znacznie spowolniłoby bardzo częstą operację.)


Wspomniałeś, że decyzja o przestrzeni nazw ma miejsce w czasie kompilacji , nie sądzę, że to prawda. z tego, czego się uczę, kompilacja Pythona sprawdza tylko błąd składniowy, a nie błąd nazwy spróbuj tego przykładu def A (): x + = 1 , jeśli go nie uruchomisz, nie da on UnboundLocalError , sprawdź dziękuję
watashiSHUN

1
Powszechnie używa się dużej litery do zmiennych globalnych, takich jakMyGlobal = 5
Vassilis

3
@watashiSHUN: Decyzja o przestrzeni nazw ma miejsce w czasie kompilacji. Decyzja, czy xjest lokalna, różni się od sprawdzania w czasie wykonywania, czy nazwa lokalna była związana z wartością przed jej pierwszym użyciem.
BlackJack

9
@Vassilis: Powszechne jest wielkimi literami wszystkich liter: MY_GLOBAL = 5. Zobacz Przewodnik po stylu dla kodu Python .
BlackJack

223

Możesz zapoznać się z pojęciem przestrzeni nazw . W Pythonie moduł jest naturalnym miejscem dla danych globalnych :

Każdy moduł ma własną prywatną tablicę symboli, która jest używana jako globalna tablica symboli przez wszystkie funkcje zdefiniowane w module. Tak więc autor modułu może używać zmiennych globalnych w module bez obawy o przypadkowe zderzenia ze zmiennymi globalnymi użytkownika. Z drugiej strony, jeśli wiesz, co robisz, możesz dotknąć zmiennych globalnych modułu jest z tej samej notacji używane w odniesieniu do jego funkcji modname.itemname.

Konkretne zastosowanie globalnego modułu jest opisane tutaj - Jak współdzielić zmienne globalne między modułami? , a dla kompletności treść jest udostępniana tutaj:

Kanonicznym sposobem udostępniania informacji między modułami w ramach jednego programu jest utworzenie specjalnego modułu konfiguracyjnego (często nazywanego config lub cfg ). Wystarczy zaimportować moduł konfiguracji do wszystkich modułów aplikacji; moduł staje się dostępny jako nazwa globalna. Ponieważ istnieje tylko jedna instancja każdego modułu, wszelkie zmiany dokonane w obiekcie modułu są odzwierciedlane wszędzie. Na przykład:

Plik: config.py

x = 0   # Default value of the 'x' configuration setting

Plik: mod.py

import config
config.x = 1

Plik: main.py

import config
import mod
print config.x

1
z jakiegoś powodu nie podoba config.x mi się to, czy mogę się go pozbyć? Przyszedłem z, x = lambda: config.xa potem mam nową wartość w x(). z jakiegoś powodu posiadanie mnie a = config.xnie rozwiązuje problemu.
vladosaurus

3
@ vladosaurus from config import xrozwiązuje to?
jylands

93

Python używa prostej heurystyki, aby zdecydować, z którego zakresu powinna załadować zmienną, między lokalną a globalną. Jeśli nazwa zmiennej pojawia się po lewej stronie przypisania, ale nie jest deklarowana jako globalna, zakłada się, że jest lokalna. Jeśli nie pojawia się po lewej stronie zadania, przyjmuje się, że ma charakter globalny.

>>> 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        
>>> 

Zobacz, jak baz, który pojawia się po lewej stronie przypisania w foo(), jest jedyną LOAD_FASTzmienną.


12
Heurystyka szuka operacji wiążących . Przypisanie to jedna taka operacja, importowanie innej. Ale cel z forpętli i nazwisko po asw withi exceptwypowiedzi również są zobowiązane do.
Martijn Pieters

@MartijnPieters dla nazwy po asw exceptklauzuli nie było to dla mnie oczywiste. Ale jest automatycznie usuwany, aby zaoszczędzić pamięć.
Robert

1
@Robert: nie w celu oszczędzania pamięci, ale w celu uniknięcia tworzenia cyklicznego odwołania, które może prowadzić do wycieków pamięci. Dzieje się tak, ponieważ wyjątek odwołuje się do śledzenia, a śledzenie odwołuje się do każdej lokalnej i globalnej przestrzeni nazw wzdłuż całego stosu wywołań, w tym do as ...celu w procedurze obsługi wyjątków.
Martijn Pieters

62

Jeśli chcesz odwoływać się do zmiennej globalnej w funkcji, możesz użyć słowa kluczowego global, aby zadeklarować, które zmienne są globalne. Nie musisz go używać we wszystkich przypadkach (jak ktoś tutaj błędnie twierdzi) - jeśli nazwy, do której odwołuje się wyrażenie, nie można znaleźć w zasięgu lokalnym lub zakresach w funkcjach, w których ta funkcja jest zdefiniowana, jest sprawdzana wśród globalnych zmienne.

Jeśli jednak przypiszesz do nowej zmiennej, która nie jest zadeklarowana jako globalna w funkcji, zostanie ona domyślnie zadeklarowana jako lokalna i może przyćmić dowolną istniejącą zmienną globalną o tej samej nazwie.

Przydatne są także zmienne globalne, w przeciwieństwie do fanatyków OOP, którzy twierdzą inaczej - szczególnie w przypadku mniejszych skryptów, w których OOP jest przesadą.


Absolutnie ponownie. fanatycy. Większość użytkowników Pythona używa go do tworzenia skryptów i tworzy małe funkcje do oddzielania małych fragmentów kodu.
Paul Uszak

51

Jeśli utworzę zmienną globalną w jednej funkcji, jak mogę użyć tej zmiennej w innej funkcji?

Możemy stworzyć globalny za pomocą następującej funkcji:

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' 

Napisanie funkcji tak naprawdę nie uruchamia jej kodu. Dlatego nazywamy create_global_variablefunkcję:

>>> create_global_variable()

Używanie globałów bez modyfikacji

Możesz po prostu z niego korzystać, o ile nie spodziewasz się zmienić obiektu, na który wskazuje:

Na przykład,

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

a teraz możemy użyć zmiennej globalnej:

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

Modyfikacja zmiennej globalnej z wnętrza funkcji

Aby wskazać zmienną globalną na inny obiekt, musisz ponownie użyć słowa kluczowego global:

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

Zauważ, że po napisaniu tej funkcji kod, który ją zmienia, wciąż nie działa:

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

Po wywołaniu funkcji:

>>> change_global_variable()

widzimy, że zmienna globalna została zmieniona. global_variableNazwa wskazuje teraz 'Bar':

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

Zauważ, że „globalny” w Pythonie nie jest tak naprawdę globalny - jest tylko globalny do poziomu modułu. Jest więc dostępny tylko dla funkcji zapisanych w modułach, w których jest globalny. Funkcje zapamiętują moduł, w którym zostały napisane, więc kiedy są eksportowane do innych modułów, nadal szukają modułu, w którym zostały utworzone, aby znaleźć zmienne globalne.

Zmienne lokalne o tej samej nazwie

Jeśli utworzysz zmienną lokalną o tej samej nazwie, przyćmi ona zmienną globalną:

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!!!'

Ale użycie tej źle nazwanej zmiennej lokalnej nie zmienia zmiennej globalnej:

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

Pamiętaj, że powinieneś unikać używania lokalnych zmiennych o takich samych nazwach jak globale, chyba że wiesz dokładnie, co robisz i masz bardzo dobry powód, aby to zrobić. Nie spotkałem jeszcze takiego powodu.

Takie samo zachowanie uzyskujemy na zajęciach

W komentarzu pojawia się pytanie:

co zrobić, jeśli chcę utworzyć zmienną globalną wewnątrz funkcji w klasie i chcę użyć tej zmiennej w innej funkcji w innej klasie?

Tutaj pokazuję, że uzyskujemy takie samo zachowanie w metodach, jak w przypadku zwykłych funkcji:

class Foo:
    def foo(self):
        global global_variable
        global_variable = 'Foo'

class Bar:
    def bar(self):
        return global_variable + '!!!'

Foo().foo()

I teraz:

>>> Bar().bar()
'Foo!!!'

Proponuję jednak zamiast używać zmiennych globalnych używać atrybutów klas, aby uniknąć zaśmiecania przestrzeni nazw modułów. Zauważ też, że nie używamy selftutaj argumentów - mogą to być metody klasowe (przydatne, gdy mutujemy atrybut klasy ze zwykłego clsargumentu) lub metody statyczne (nie selflub cls).


Fajnie, ale co zrobić, jeśli chcę utworzyć zmienną globalną wewnątrz funkcji w klasie i chcę użyć tej zmiennej w innej funkcji w innej klasie? Trochę tu utknąłem
anonmanx

2
@ anonmanx Nie wiem, dlaczego utknąłeś, jest to takie samo zachowanie w metodzie, jak w zwykłej funkcji. Ale zaktualizuję moją odpowiedź z twoją uwagą i kodem demonstracyjnym, dobrze?
Aaron Hall

1
@anonmanx jak to jest?
Aaron Hall

okej, rozumiem Będę musiał jawnie wywołać tę funkcję w celu użycia tej zmiennej globalnej.
anonmanx

47

Oprócz już istniejących odpowiedzi i aby było to bardziej mylące:

W Pythonie zmienne, do których odwołuje się tylko funkcja, są domyślnie globalne . Jeśli zmiennej przypisano nową wartość w dowolnym miejscu w ciele funkcji, zakłada się, że jest ona lokalna . Jeśli zmienna kiedykolwiek ma przypisaną nową wartość w funkcji, zmienna jest domyślnie lokalna i musisz jawnie zadeklarować ją jako „globalną”.

Choć na początku trochę zaskakujące, moment zastanowienia wyjaśnia to. Z jednej strony, wymaganie globalne dla przypisanych zmiennych zapewnia pasek przeciw niezamierzonym skutkom ubocznym. Z drugiej strony, gdyby globalny był wymagany dla wszystkich globalnych odniesień, cały czas będziesz używać globalnego. Będziesz musiał zadeklarować jako globalne każde odwołanie do wbudowanej funkcji lub komponentu importowanego modułu. Ten bałagan pokonałby przydatność globalnej deklaracji do identyfikowania skutków ubocznych.

Źródło: Jakie są reguły dla zmiennych lokalnych i globalnych w Pythonie? .


34

Przy równoległym wykonywaniu zmienne globalne mogą powodować nieoczekiwane wyniki, jeśli nie rozumiesz, co się dzieje. Oto przykład użycia zmiennej globalnej w ramach wieloprocesowego przetwarzania. Widzimy wyraźnie, że każdy proces działa z własną kopią zmiennej:

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))

Wynik:

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]

25

Mówisz o użyciu następującej metody:

globvar = 5

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

f()  # Prints 5

Ale lepszym sposobem jest użycie globalnej zmiennej w ten sposób:

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

Oba dają taką samą moc wyjściową.


25

Jak się okazuje, odpowiedź jest zawsze prosta.

Oto mały przykładowy moduł z prostym sposobem pokazania go w maindefinicji:

def five(enterAnumber,sumation):
    global helper
    helper  = enterAnumber + sumation

def isTheNumber():
    return helper

Oto jak to pokazać w maindefinicji:

import TestPy

def main():
    atest  = TestPy
    atest.five(5,8)
    print(atest.isTheNumber())

if __name__ == '__main__':
    main()

Ten prosty kod działa w ten sposób i zostanie wykonany. Mam nadzieję, że to pomoże.


1
dzięki, jestem nowy w Pythonie, ale znam trochę Java. to co powiedziałeś, działało dla mnie. i napisanie globalnego <ENTER> w klasie .. wydaje mi się bardziej sensowne niż w funkcji piszącej „globalny a” ..
Zauważam,

2
Jest to prawdopodobnie najprostsza, ale bardzo przydatna sztuczka dla Pythona. Nazywam ten moduł global_varsi inicjuję dane init_global_vars, które są wywoływane w skrypcie startowym. Następnie po prostu tworzę metodę akcesora dla każdej zdefiniowanej zmiennej globalnej. Mam nadzieję, że będę mógł to głosować wiele razy! Dzięki Peter!
swdev

1
Co się stanie, jeśli istnieje wiele zmiennych globalnych i nie chcę ich wymieniać jeden po drugim po wyciągu globalnym?
jtlz2

23

Musisz odwoływać się do zmiennej globalnej w każdej funkcji, której chcesz użyć.

Następująco:

var = "test"

def printGlobalText():
    global var #wWe are telling to explicitly use the global version
    var = "global from printGlobalText fun."
    print "var from printGlobalText: " + var

def printLocalText():
    #We are NOT telling to explicitly use the global version, so we are creating a local variable
    var = "local version from printLocalText fun"
    print "var from printLocalText: " + var

printGlobalText()
printLocalText()
"""
Output Result:
var from printGlobalText: global from printGlobalText fun.
var from printLocalText: local version from printLocalText
[Finished in 0.1s]
"""

3
„w każdej funkcji, której chcesz użyć” jest subtelnie niepoprawny, powinien być bliżej: „w każdej funkcji, w której chcesz zaktualizować
spazm

21

W rzeczywistości nie przechowujesz globalnego w zmiennej lokalnej, po prostu tworzysz lokalne odwołanie do tego samego obiektu, do którego odnosi się twoje oryginalne odwołanie globalne. Pamiętaj, że prawie wszystko w Pythonie jest nazwą odnoszącą się do obiektu i nic nie jest kopiowane podczas zwykłej operacji.

Jeśli nie musisz jawnie określać, kiedy identyfikator ma odnosić się do predefiniowanej globalnej, prawdopodobnie musiałbyś jawnie określić, kiedy identyfikator jest nową zmienną lokalną (na przykład za pomocą czegoś takiego jak polecenie „var” widoczne w JavaScript). Ponieważ zmienne lokalne są bardziej powszechne niż zmienne globalne w dowolnym poważnym i nietrywialnym systemie, w większości przypadków system Pythona ma większy sens.

Państwo mogłoby mieć język, który próbował odgadnąć, wykorzystując zmienną globalną gdyby istniał lub utworzenie zmiennej lokalnej, czy nie. Byłoby to jednak bardzo podatne na błędy. Na przykład zaimportowanie innego modułu może przypadkowo wprowadzić zmienną globalną o tej nazwie, zmieniając zachowanie twojego programu.


17

Spróbuj tego:

def x1():
    global x
    x = 6

def x2():
    global x
    x = x+1
    print x

x = 5
x1()
x2()  # output --> 7


14

Następnie i jako dodatek użyj pliku, który zawiera wszystkie zmienne globalne wszystkie zadeklarowane lokalnie, a następnie import as:

Plik initval.py :

Stocksin = 300
Prices = []

Plik getstocks.py :

import initval as iv

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


def getmycharts():
    for ic in range(iv.Stocksin):

1
Jaka jest zaleta przeniesienia zmiennych globalnych do innego pliku? Czy to po prostu zgrupować globalne zmienne w małym pliku? A po co używać oświadczenia import ... as ...? Dlaczego nie tylko import ...?
olibre

1
Ach ... W końcu zrozumiałem zaletę: Nie trzeba używać słowa kluczowego global:-) => +1 :-) Edytuj swoją odpowiedź, aby wyjaśnić te zapytania, które mogą mieć także inni ludzie. Pozdrawiam
olibre

13

Zapis do jawnych elementów tablicy globalnej najwyraźniej nie wymaga globalnej deklaracji, chociaż zapis do niej „hurtowy” ma ten wymóg:

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

7

Dodam to, ponieważ nie widziałem tego w żadnej innej odpowiedzi i może być przydatne dla kogoś, kto zmaga się z czymś podobnym. globals()Funkcja zwraca zmienny słownika globalny symbol, gdzie można „magicznie” dostępne do reszty kodu dane wprowadzić. Na przykład:

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

i

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

Pozwoli tylko zrzucić / załadować zmienne zi do globalnej przestrzeni nazw. Super wygodne, bez musków, bez zamieszania. Jestem pewien, że to tylko Python 3.


3
globals()zawsze zwraca globały dostępne w kontekście lokalnym, więc mutacja tutaj może nie zostać odzwierciedlona w innym module.
Kiran Jonnalagadda,

6

Odwołaj się do przestrzeni nazw klas, w której chcesz pokazać zmianę.

W tym przykładzie runner używa max z konfiguracji pliku. Chcę, aby mój test zmienił wartość maks gdy biegacz go używa.

main / config.py

max = 15000

main / runner.py

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

testy / 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()

1

Globale są w porządku - z wyjątkiem wieloprocesowego

Globalne w związku z wieloprocesowym przetwarzaniem na różnych platformach / środowiskach, takich jak Windows / Mac OS z jednej strony i Linux z drugiej, są kłopotliwe.

Pokażę to na prostym przykładzie, wskazując problem, na który wpadłem jakiś czas temu.

Jeśli chcesz zrozumieć, dlaczego sprawy różnią się w systemach Windows / MacO i Linux, musisz to wiedzieć, domyślny mechanizm uruchamiania nowego procesu w ...

  • Windows / MacO to „spawn”
  • Linux to „widelec”

Różnią się one inicjalizacją przydziału pamięci ... (ale nie wchodzę w to tutaj).

Rzućmy okiem na problem / przykład ...

import multiprocessing

counter = 0

def do(task_id):
    global counter
    counter +=1
    print(f'task {task_id}: counter = {counter}')

if __name__ == '__main__':

    pool = multiprocessing.Pool(processes=4)
    task_ids = list(range(4))
    pool.map(do, task_ids)

Windows

Jeśli uruchomisz to w systemie Windows (i przypuszczam, że także w systemie MacOS), otrzymasz następujące dane wyjściowe ...

task 0: counter = 1
task 1: counter = 2
task 2: counter = 3
task 3: counter = 4

Linux

Jeśli uruchomisz to w systemie Linux, zamiast tego otrzymasz następujące.

task 0: counter = 1
task 1: counter = 1
task 2: counter = 1
task 3: counter = 1
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.