Pytanie Używanie zmiennych globalnych w funkcji


Jak 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 dostępu?


2478
2018-01-08 05:45


pochodzenie




Odpowiedzi:


Możesz użyć zmiennej globalnej w innych funkcjach, deklarując ją jako global w każdej przypisanej funkcji:

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 jest to, że ponieważ zmienne globalne są tak niebezpieczne, Python chce mieć pewność, że naprawdę wiecie, że to jest to, z czym gracie, wyraźnie wymagając global słowo kluczowe.

Zobacz inne odpowiedzi, jeśli chcesz udostępnić zmienną globalną w modułach.


3509
2018-01-08 08:39



To skrajna przesada, by odnosić się do globałów jako "tak niebezpiecznych". Globale są doskonale w każdym języku, jaki kiedykolwiek istniał i kiedykolwiek będzie istnieć. Mają swoje miejsce. Powinniście powiedzieć, że mogą powodować problemy, jeśli nie macie pojęcia, jak programować. - Anthony
Myślę, że są dość niebezpieczne. Jednak w python "globalne" zmienne są faktycznie na poziomie modułu, który rozwiązuje wiele problemów. - Fábio Santos
Nie zgadzam się z tym, że powód, dla którego Python wymaga global słowo kluczowe jest takie, że globale są niebezpieczne. Jest tak raczej dlatego, że język nie wymaga jawnego deklarowania zmiennych i automatycznie zakłada, że ​​przypisana zmienna ma zasięg funkcji, chyba że powiesz mu inaczej. The global słowo kluczowe to sposób, który jest podawany, aby powiedzieć mu inaczej. - Nate C-K
Zmienne globalne to zapach wzornictwa, w prawie każdym języku, którego używałem profesjonalnie. Powiedzmy, że masz funkcję, która pobiera trzy bajty: To 8 możliwych ścieżek do sprawdzenia. Jeśli masz 3 funkcje z taką samą liczbą argumentów logicznych, to 24 możliwe ścieżki kodu. Następnie dodaj jedną globalną zmienną boolowską, teraz patrzysz na 24 ^ 2 możliwych ścieżek kodu, ponieważ musisz uwzględnić fakt, że WSZYSTKIE funkcje mają możliwość zmiany stanu tej globalnej zmiennej. Właśnie dlatego popularne stały się techniki programowania funkcjonalnego. - avgvstvs
@LightnessRacesinOrbit Nie rozumiem. Jeśli usuniesz zmienną globalną, usuniesz teraz czynnik komplikujący, dowolne funkcje nie mogą już zmieniać stanu programu, w różnych punktach wykonania - w ten sposób zmieniając wykonanie w sposób, który z innych względów jest niewidoczny dla innych funkcji, które opierają się na tej zmiennej. Nie musisz już śledzić, "Zrobiłeś f2() zmień teraz stan f3() może zrobić coś nieoczekiwanego? Funkcje mogą teraz działać agnostycznie do zewnętrznego stanu programu. - avgvstvs


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

Załóżmy, że masz moduł podobny do tego:

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

Możesz oczekiwać, że wydrukuje 42, ale zamiast tego wypisze 5. Jak już wspomniano, jeśli dodasz 'global"Deklaracja dla func1(), następnie func2() wydrukuje 42.

def func1():
    global myGlobal
    myGlobal = 42

To, co się tutaj dzieje, to to, że Python zakłada to dowolne imię przypisane dogdziekolwiek w obrębie funkcji jest lokalna dla tej funkcji, chyba że wyraźnie powiedziano inaczej. Jeśli jest tylko czytanie od nazwy, a nazwa nie istnieje lokalnie, spróbuje wyszukać nazwę w dowolnych zakresach (np. globalny zasięg modułu).

Po przypisaniu 42 do nazwy myGlobaldlatego też Python tworzy lokalną zmienną, która cienia globalną zmienną o tej samej nazwie. To lokalne wykracza poza zakres i jest zbierane śmieci gdy func1() zwraca; W międzyczasie, func2() nigdy nie może zobaczyć niczego poza (niezmodyfikowaną) nazwą globalną. Zauważ, że decyzja o przestrzeni nazw odbywa się w czasie kompilacji, a nie w środowisku wykonawczym - jeśli chcesz odczytać wartość myGlobal wewnątrz func1() przed przypisaniem jej, dostaniesz UnboundLocalError, ponieważ Python już zdecydował, że musi to być zmienna lokalna, ale nie ma jeszcze żadnej powiązanej z nią wartości. Ale używając "global"oświadczenie, mówisz Pythonowi, że powinien szukać gdzie indziej nazwy zamiast przypisywać ją lokalnie.

(Sądzę, że to zachowanie powstało głównie dzięki optymalizacji lokalnych przestrzeni nazw - bez takiego zachowania, maszyna wirtualna Pythona musiałaby wykonywać co najmniej trzy wyszukiwania nazw za każdym razem, gdy do funkcji przypisano nową nazwę (aby upewnić się, że nazwa nie zawierała nazwy). t już istnieje na poziomie modułu / wbudowanym), co znacznie spowolniłoby bardzo powszechną operację.)


661
2018-01-08 09:19



Wspomniałeś, że decyzja o przestrzeni nazw ma miejsce czas kompilacji, Nie sądzę, że to prawda. z tego, czego się nauczyłem, kompilacji Pythona tylko sprawdza błąd składni, a nie błąd nazwy spróbuj tego przykładu def A (): x + = 1, jeśli go nie uruchomisz, będzie nie daje UnboundLocalError, proszę potwierdzić dziękuję - watashiSHUN
Powszechne jest używanie wielkiej litery dla zmiennych globalnych, takich jak MyGlobal = 5 - Vassilis
@watashiSHUN: Decyzja o przestrzeni nazw robi zdarzyć się w czasie kompilacji. Decydując się na to x local jest inny niż sprawdzanie w środowisku wykonawczym, jeśli nazwa lokalna została powiązana z wartością, zanim zostanie użyta za pierwszym razem. - BlackJack
@Vassilis: Jest to typowe dla wielkich liter wszystko listy: MY_GLOBAL = 5. Zobacz Przewodnik po stylu dla kodu Pythona. - BlackJack
@BlackJack, tak stary, masz rację! (Jestem przyzwyczajony do c) - Vassilis


Możesz chcieć poznać pojęcie przestrzenie nazw. W języku Python moduł jest naturalnym miejscem dla światowy dane:

Każdy moduł ma swoją własną tablicę symboli, która jest używana jako globalna tablica symboli przez wszystkie funkcje zdefiniowane w module. W ten sposób 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 z tą samą notacją, które odnoszą się do jej funkcji, modname.itemname.

Określone zastosowanie modułu globalnego w module jest opisane tutaj - how-do-i-share-global-variables-across-modules, a dla kompletności zawartość jest udostępniana tutaj:

Kanonicznym sposobem udostępniania informacji pomiędzy modułami w ramach jednego programu jest utworzenie specjalnego modułu konfiguracyjnego (często nazywanego config lub cfg). Wystarczy zaimportować moduł konfiguracyjny do wszystkich modułów aplikacji; moduł staje się dostępny jako nazwa globalna. Ponieważ istnieje tylko jedno wystąpienie każdego modułu, wszelkie zmiany dokonane w obiekcie modułu są odzwierciedlone 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

175
2018-01-08 05:59



z tego powodu nie lubię tego config.x  czy mogę się tego pozbyć? Przyszedłem z x = lambda: config.x a potem mam Nowy wartość w x(). z jakiegoś powodu, mając a = config.x nie dla mnie. - vladosaurus


Python używa prostego algorytmu heurystycznego, aby zdecydować, który zakres powinien załadować zmienną z, między lokalną i globalną. Jeśli nazwa zmiennej pojawi się po lewej stronie przypisania, ale nie zostanie uznana za globalną, przyjmuje się, że jest ona lokalna. Jeśli nie pojawi się po lewej stronie przypisania, zakłada się, że jest 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 działa baz, który pojawia się po lewej stronie zadania foo(), jest jedynym LOAD_FAST zmienna.


75
2017-07-12 12:35



Heurystyczne szuka operacje wiążące. Przypisanie to jedna z takich operacji, importująca inną. Ale celem for pętla i imię po as w with i except są również powiązane z instrukcjami. - Martijn Pieters♦


Jeśli chcesz odnieść się do zmiennej globalnej w funkcji, możesz użyć światowy słowo kluczowe, aby zadeklarować, które zmienne są globalne. Nie musisz go używać we wszystkich przypadkach (jak ktoś tutaj niepoprawnie twierdzi) - jeśli nazwy odwołującej się w wyrażeniu nie można znaleźć w zasięgu lokalnym lub zakresach w funkcjach, w których ta funkcja jest zdefiniowana, jest ona porównywana zmienne.

Jeśli jednak przypiszemy do nowej zmiennej, która nie została 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.

Również zmienne globalne są użyteczne, w przeciwieństwie do niektórych fanatyków OOP, którzy twierdzą inaczej - zwłaszcza w przypadku mniejszych skryptów, gdzie OOP jest przesadny.


48
2018-01-08 09:03





Oprócz już istniejących odpowiedzi i sprawienia, że ​​będzie to bardziej mylące:

W języku Python zmiennymi, które są przywoływane tylko wewnątrz funkcji    domyślnie globalny. Jeśli zmiennej zostanie przypisana nowa wartość w dowolnym miejscu   w ciele funkcji zakłada się, że jest lokalny. Jeśli zmienna   jest zawsze przypisana nowa wartość wewnątrz funkcji, zmienna jest   domyślnie lokalny i musisz jawnie zadeklarować go jako "globalny".

Choć początkowo trochę zaskakujące, wyjaśnia moment rozważania   to. Z jednej strony, wymaganie globalnego dla przypisanych zmiennych zapewnia   przeciw niepożądanym działaniom ubocznym. Z drugiej strony, jeśli globalny był   wymagane dla wszystkich globalnych odniesień, używałbyś globalnego wszystkiego   czas. Będziesz musiał zadeklarować jako globalne każde odniesienie do wbudowanego   funkcja lub składnik importowanego modułu. To bałagan będzie   pokonać użyteczność globalnej deklaracji do identyfikacji   skutki uboczne.

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


36
2017-07-04 10:23





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

Możemy stworzyć globalną z następującą funkcją:

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' 

Zapisywanie funkcji w rzeczywistości nie uruchamia swojego kodu. Więc nazywamy to create_global_variable funkcjonować:

>>> create_global_variable()

Używanie globali bez modyfikacji

Możesz go po prostu użyć, o ile nie spodziewasz się zmienić, który obiekt 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 skierować zmienną globalną na inny obiekt, należy ponownie użyć słowa kluczowego global:

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

Zauważ, że po zapisaniu tej funkcji kod, który faktycznie się zmienia, nadal nie działa:

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

Po wywołaniu funkcji:

>>> change_global_variable()

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

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

Zauważ, że "globalny" w Pythonie nie jest prawdziwie globalny - jest tylko globalny do poziomu modułu. Jest więc dostępna tylko dla funkcji napisanych w modułach, w których jest globalna. Funkcje pamiętają moduł, w którym są napisane, więc gdy są eksportowane do innych modułów, wciąż szukają w module, w którym zostały utworzone, aby znaleźć globalne zmienne.

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 błędnie nazwanej zmiennej lokalnej nie zmienia zmiennej globalnej:

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

Zwróć uwagę, że powinieneś unikać używania zmiennych lokalnych o takich samych nazwach jak globale, chyba że wiesz dokładnie, co robisz i masz ku temu dobry powód. Jeszcze nie spotkałem się z takiego powodu.


31
2018-01-01 19:55





Przy równoległym wykonaniu zmienne globalne mogą powodować nieoczekiwane rezultaty, jeśli nie rozumiesz, co się dzieje. Oto przykład zastosowania zmiennej globalnej w ramach przetwarzania wieloprocesowego. Możemy wyraźnie zobaczyć, ż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))

Wydajność:

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]

28
2017-10-03 05:41





Musisz odnieść 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]
"""

19
2017-12-20 12:45



"w każdej funkcji, której chcesz użyć" jest subtelnie niepoprawne, powinno być bliższe: "w każdej funkcji, gdzie chcesz aktualizacja" - spazm


To, co mówisz, to użycie tej metody:

globvar = 5

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

f()  # Prints 5

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

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

Oba dają taką samą wydajność.


19
2017-12-04 06:27



Pierwszy kod podaje błąd składni. - Fermi paradox
Dzięki @Fermiparadox Dokonałem edycji. - gxyd