Питання Використання глобальних змінних у функції


Як я можу створити або використовувати глобальну змінну в функції?

Якщо я створюю глобальну змінну в одній функції, як я можу використовувати цю глобальну змінну в іншій функції? Чи потрібно зберігати глобальну змінну у локальній змінній функції, яка потребує її доступу?


2478
2018-01-08 05:45


походження




Відповіді:


Ви можете використовувати глобальну змінну в інших функціях, оголосивши її як global у кожній призначеній йому функції:

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

Я думаю, що причиною цього є те, що оскільки глобальні змінні настільки небезпечні, Python хоче переконатися, що ви дійсно знаєте, що це те, що ви граєте, явно вимагаючи global ключове слово

Перегляньте інші відповіді, якщо хочете поділитися глобальною змінною через модулі.


3509
2018-01-08 08:39



Надзвичайним перебільшенням є посилання на глобали як "настільки небезпечні". Глобали абсолютно чудово в кожній мові, яка коли-небудь існувала і коли-небудь існує. Вони мають своє місце. Що ви повинні сказати, вони можуть викликати проблеми, якщо у вас немає поняття, як програмувати. - Anthony
Я думаю, вони досить небезпечні. Однак в python "глобальні" змінні - це на рівні модулів, що вирішує багато питань. - Fábio Santos
Я не погоджуюсь з тим, що причиною вимагає Python global ключове слово тому, що globals є небезпечними. Швидше, це тому, що мова не вимагає від вас явно оголошувати змінні, і автоматично припускає, що для змінної, яку ви призначаєте, є функція, якщо ви не скажете інше. The global ключове слово - це засіб, який надається, щоб сказати це іншим способом. - Nate C-K
Глобальні змінні - дизайнерський запах практично у всіх мовах, які я використовував професійно. Скажімо, у вас є функція, яка приймає три логіна: це 8 можливих шляхів коду для перевірки. Якщо у вас є 3 функції з тим самим числом логічних аргументів, це 24 можливих шляху коду. Потім додати одну логічну глобальну змінну, тепер ви дивитесь на 24 ^ 2 можливих кодів шляху, тому що ви повинні облік того факту, що всі функції мають можливість змінювати стан цієї глобальної змінної. Ось чому технології функціонального програмування стали популярними. - avgvstvs
@LightnessRacesinOrbit Я не отримую вашої думки. Якщо ви видалите глобальну змінну, ви видалите фактор ускладнення в цьому, тепер довільні функції більше не можуть змінити стан програми, в різних пунктах виконання - таким чином змінюючи виконання таким чином, що в іншому випадку непомітно для інших функцій, що залежать від цієї змінної. Вам більше не доведеться стежити за тим, "зробив" f2() змінити стан так зараз f3() може зробити щось несподіване? Функції тепер можуть управляти агностиком до зовнішнього стану програми. - avgvstvs


Якщо я правильно розумію вашу ситуацію, то, що ви бачите, є результатом того, як Python обробляє локальні (функціональні) та глобальні (модульні) області імен.

Скажімо, у вас є такий модуль:

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

Ви можете очікувати, що друкуватиметься 42, але замість цього він надрукує 5. Як вже було сказано, якщо ви додаєте "globalдекларація до func1(), потім func2() надрукує 42.

def func1():
    global myGlobal
    myGlobal = 42

Тут відбувається те, що Python припускає, що будь-яке ім'я, яке є присвоєно, де-небудь у межах функції, є локальною для цієї функції, якщо явно не вказано інше. Якщо це тільки читання від імені, а ім'я не існує локально, він намагатиметься знайти назву в будь-яких областях (наприклад, глобальний масштаб модуля).

Коли ви призначаєте 42 для імені myGlobal, тому Python створює локальну змінну, яка затінює глобальну змінну з тим самим ім'ям. Той місцевий виходить за рамки і є зібрані сміття коли func1() повертає; Тим часом func2() ніколи не побачить нічого, крім (незмінених) глобального імені. Зверніть увагу, що це рішення імен простір відбувається під час компіляції, а не під час виконання - якщо ви хочете прочитати значення myGlobal всередині func1() перш ніж призначити йому, ви отримаєте UnboundLocalError, оскільки Python вже вирішив, що вона повинна бути локальною змінною, але вона ще не має жодної вартості, пов'язаної з нею. Але, використовуючи "global'вислів, ви повідомляєте Python, що він має шукати в іншому місці ім'я, а не призначати його локально.

(Я вважаю, що така поведінка виникла в основному завдяки оптимізації локальних областей імен - без цієї поведінки VM Python повинен виконувати щонайменше три назви для пошуку кожного разу, коли нове ім'я призначено всередині функції (щоб переконатись, що ім'я не " t вже існує на рівні модуля / builtin), що значно сповільнило б дуже поширену операцію.)


661
2018-01-08 09:19



Ви згадали, що рішення про простір імен відбувається в скласти час, Я не думаю, що це правда. від чого я дізнаюся про компіляцію пітона перевіряє лише синтаксичну помилку, а не помилку імені спробуй цей приклад def A (): x + = 1, якщо ви не запустите його, це буде не надавати UnboundLocalError, будь ласка, перевірте спасибі - watashiSHUN
Загальноприйнято використовувати велику букву для глобальних змінних, таких як MyGlobal = 5 - Vassilis
@watashiSHUN: рішення про простір імен робить відбудеться у час компіляції. Вирішивши це x локальний відрізняється від перевірки під час виконання, якщо локальне ім'я було пов'язано з значенням, перш ніж він буде використовуватися вперше. - BlackJack
@Вассіліс: це звичайно для верхнього регістру все листи: MY_GLOBAL = 5. Див Стиль керівництва для коду Python. - BlackJack
@BlackJack, так, чоловік, ти маєш рацію! (Я звик c) - Vassilis


Ви можете вивчити поняття простір імен. У Python, The модуль є природним місцем для глобальний дані:

Кожен модуль має свою власну таблицю символів, яка використовується як глобальна таблиця символів за всіма функціями, визначеними в модулі. Таким чином, автор модуля може використовувати глобальні змінні в модулі, не турбуючись про випадкові зіткнення з глобальними змінними користувача. З іншого боку, якщо ви знаєте, що ви робите, ви можете торкнутися глобальних змінних модуля з тією ж позначеннями, які використовуються для позначення його функцій, modname.itemname.

Тут описано специфічне використання глобального в-модулі - how-do-i-share-global-variables-across-modules, і для повноти вміст використовується тут:

Канонічний спосіб обміну інформацією між модулями всередині однієї програми полягає у створенні спеціального модуля конфігурації (часто називається config або cfg). Просто імпортуйте модуль конфігурації у всі модулі вашої програми; потім модуль стане доступним як глобальне ім'я. Оскільки існує лише один екземпляр кожного модуля, будь-які зміни, внесені в об'єкт модуля, відображаються скрізь. Наприклад:

Файл: config.py

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

Файл: mod.py

import config
config.x = 1

Файл: main.py

import config
import mod
print config.x

175
2018-01-08 05:59



з причини мені не подобається config.x  Чи можу я позбутися від цього? Я прийшов з x = lambda: config.x а потім у мене є новий значення в x(). чомусь, маючи a = config.x не робить для мене трюку. - vladosaurus


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(), є єдиним LOAD_FAST змінна


75
2017-07-12 12:35



Евристичний шукає обов'язкові операції. Призначення є однією з таких операцій, імпортуючи інше. Але ціль а for петля та ім'я після as в with і except заяви також зобов'язані. - Martijn Pieters♦


Якщо ви хочете послатися на глобальну змінну в функції, ви можете використовувати глобальний ключове слово, щоб оголосити, які змінні глобальні. Ви не повинні використовувати його в усіх випадках (як хтось тут неправильно стверджує) - якщо ім'я, на яке посилається вираз, не може бути знайдено в локальній області чи області функцій, в яких ця функція визначена, її шукають серед глобальних змінні.

Однак, якщо ви призначите нову змінну, не оголошену глобальною у функції, вона неявно оголошується локальною, і вона може затьмарити будь-яку існуючу глобальну змінну з таким самим ім'ям.

Крім того, глобальні змінні корисні, всупереч деяким репресованим ООП, які заявляють про інше - особливо для невеликих скриптів, де ООП є надмірно важливим.


48
2018-01-08 09:03





На додаток до вже наявних відповідей і зробити це більш заплутаним:

У Python змінні, на які посилаються лише функції, є    неявно глобальний. Якщо для змінної призначено нове значення в будь-якому місці   в межах тіла функції це передбачається а місцевий. Якщо є змінна   колись призначається нове значення усередині функції, змінною є   неявно локальний, і ви повинні явно оголосити його "глобальним".

Хоча спочатку трохи дивно, мислення пояснюється   це. З одного боку, вимагаючи глобальних для призначених змінних, забезпечується a   бар проти небажаних побічних ефектів. З іншого боку, якщо б був глобальний   необхідний для всіх глобальних посилань, ви будете використовувати глобальні всі   час Ви повинні оголосити як глобальне кожне посилання на вбудований   функцію або компоненту імпортованого модуля. Це безлад було б   перемогти корисність глобальної декларації для виявлення   побічні ефекти.

Джерело: Які правила для локальних та глобальних змінних в Python?.


36
2017-07-04 10:23





Якщо я створюю глобальну змінну в одній функції, як я можу використовувати цю змінну в іншій функції?

Ми можемо створити глобальний з наступною функцією:

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

Використання globals без модифікації

Ви можете просто використовувати його, поки ви не очікуєте змінити який об'єкт він вказує:

Наприклад,

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

ми бачимо, що глобальна змінна була змінена. The global_variable ім'я тепер вказує на 'Bar':

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

Зауважте, що "глобальний" в Python не справді глобальний - це лише глобальний рівень модуля. Таким чином, вона доступна лише для функцій, написаних у модулях, в яких вона глобальна. Функції запам'ятовують модуль, в якому вони написані, тому, коли вони експортуються в інші модулі, вони все ще шукають модуль, в якому вони були створені, щоб знайти глобальні змінні.

Локальні змінні з однаковим ім'ям

Якщо ви створите локальну змінну з тим самим ім'ям, вона затінює глобальну змінну:

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

Зауважте, що вам слід уникати використання локальних змінних з тими самими іменами, як globals, якщо ви точно не знаєте, що ви робите, і маєте дуже вагомі підстави для цього. Я ще не зіткнувся з такою причиною.


31
2018-01-01 19:55





З паралельним виконанням глобальні змінні можуть викликати несподівані результати, якщо ви не розумієте, що відбувається. Ось приклад використання глобальної змінної в рамках багатопроцесорної обробки. Ми чітко бачимо, що кожен процес працює з власною копією змінної:

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]

28
2017-10-03 05:41





Вам потрібно вказати глобальну змінну у кожній функції, яку ви хочете використовувати.

Таким чином:

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



"у кожній функції, яку ви хочете використовувати", є тонко неправильною, має бути ближче до: "у кожній функції, де ви хочете оновлення' - spazm


Те, що ви кажете, це використовувати такий спосіб:

globvar = 5

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

f()  # Prints 5

Але кращим способом є використання такої глобальної змінної:

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

Обидва дають однаковий вихід.


19
2017-12-04 06:27



Перший код дає синтаксичну помилку. - Fermi paradox
Спасибі @ Fermiparadox Я зробив редагування. - gxyd