Функції глобальних змінних Python?


271

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

x = "somevalue"

def func_A ():
   global x
   # Do things to x
   return x

def func_B():
   x = func_A()
   # Do things
   return x

func_A()
func_B()

Чи те, xщо використовує друга функція, має однакове значення глобальної копії, xяка func_aвикористовує та модифікує? Коли дзвінки функцій після визначення, чи має значення порядок?


1
будьте обережні і не припускайте лише тому, що у вашій функції призначена змінна, що python буде розглядати посилання перед призначенням як таке. До першого призначення, якщо ви використовували х, воно не було б глобальним чи локальним. Ви отримаєте сумнозвісне виключення UnboundLocalError у своєму обличчі :)
osirisgothra

Відповіді:


412

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

Напр

global someVar
someVar = 55

Це змінило б значення глобальної змінної на 55. В іншому випадку вона просто призначить 55 локальній змінній.

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


2
У наданому мені коді func_B робить речі (1) для глобальної копії x (як отримано з func_A), (2) до локальної змінної x з тим же значенням результату func_A, або (3) до локальна змінна x без значення і (в очах компілятора) ніякого відношення до "деякого значення" або x у func_A?
Акшат Шехар

xв func_B- це локальна змінна, яка отримує своє значення від зворотного значення дзвінка до func_A- тому, мабуть, це зробить це вашим (2)
Левон

Добре, скажімо, x була випадковою послідовністю якогось роду, що генерується func_A (тобто, що func_A виробляла різні x кожен раз, коли вона була запущена.) Запуск програми, як написано, зробить func_b змінити інший х, ніж те, що було створено, коли func_a був дзвонив? Якщо так, як я можу це виправити?
Акшат Шехар

1
Так, якщо func_Aпід час кожного запуску змінюється глобальна змінна та повертає її func_Bу користування, то вона func_Bбуде працювати зі зміненим значенням кожного разу. Я не впевнений у вашому "як це виправити". Ви можете прийняти найбільш корисну відповідь на своє поточне / оригінальне запитання, а потім розглянути можливість відкрити інше питання про те, як виглядає подальше запитання.
Левон

1
Насправді це залежить від того, що таке х. Якщо x незмінний, то x у func_B залишиться в ньому, оскільки він оголошується локально, навіть якщо вони мають однакове значення. Це стосується кортежів, ints ... Якщо, наприклад, це екземпляр списку, і ви x.append("..."), це змінюється глобальна змінна x, оскільки локальна посилається на глобальну.
jadkik94

110

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

Давайте розглянемо модифіковану версію вашого псевдокоду, щоб побачити, що відбувається:

# Here, we're creating a variable 'x', in the __main__ scope.
x = 'None!'

def func_A():
  # The below declaration lets the function know that we
  #  mean the global 'x' when we refer to that variable, not
  #  any local one

  global x
  x = 'A'
  return x

def func_B():
  # Here, we are somewhat mislead.  We're actually involving two different
  #  variables named 'x'.  One is local to func_B, the other is global.

  # By calling func_A(), we do two things: we're reassigning the value
  #  of the GLOBAL x as part of func_A, and then taking that same value
  #  since it's returned by func_A, and assigning it to a LOCAL variable
  #  named 'x'.     
  x = func_A() # look at this as: x_local = func_A()

  # Here, we're assigning the value of 'B' to the LOCAL x.
  x = 'B' # look at this as: x_local = 'B'

  return x # look at this as: return x_local

Насправді, ви можете переписати все func_Bіз названою змінною, x_localі вона буде працювати однаково.

Порядок має значення лише в тому порядку, в якому ваші функції виконують операції, що змінюють значення глобального x. Таким чином, у нашому прикладі порядок не має значення, оскільки func_Bдзвонить func_A. У цьому прикладі порядок має значення:

def a():
  global foo
  foo = 'A'

def b():
  global foo
  foo = 'B'

b()
a()
print foo
# prints 'A' because a() was the last function to modify 'foo'.

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

x = 5

def access_only():
  return x
  # This returns whatever the global value of 'x' is

def modify():
  global x
  x = 'modified'
  return x
  # This function makes the global 'x' equal to 'modified', and then returns that value

def create_locally():
  x = 'local!'
  return x
  # This function creates a new local variable named 'x', and sets it as 'local',
  #  and returns that.  The global 'x' is untouched.

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

Тут плутанина, чому ви не повинні використовувати глобальні змінні.


2
Я не думаю, що це дуже заплутано на практиці, ви просто повинні зрозуміти правила розміщення пітона .
Кейсі Кубалл

20

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

Щоб детальніше розібратися в цьому, що означає "модифікувати", це таке: якщо ви хочете повторно пов'язати глобальне ім'я, щоб воно вказувало на інший об'єкт, ім'я повинно бути оголошено globalу функції.

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

d = {}
l = []
o = type("object", (object,), {})()

def valid():     # these are all valid without declaring any names global!
   d[0] = 1      # changes what's in d, but d still points to the same object
   d[0] += 1     # ditto
   d.clear()     # ditto! d is now empty but it`s still the same object!
   l.append(0)   # l is still the same list but has an additional member
   o.test = 1    # creating new attribute on o, but o is still the same object

8

Ось один випадок, який мене зловив, використовуючи глобальне значення за замовчуванням параметра.

globVar = None    # initialize value of global variable

def func(param = globVar):   # use globVar as default value for param
    print 'param =', param, 'globVar =', globVar  # display values

def test():
    global globVar
    globVar = 42  # change value of global
    func()

test()
=========
output: param = None, globVar = 42

Я очікував, що парам має значення 42. Сюрприз. Python 2.7 оцінював значення globVar під час першого розбору функції func. Зміна значення globVar не вплинула на значення за замовчуванням, призначене для парам. Затримка оцінки, як і в наступному, працювала так, як мені потрібно.

def func(param = eval('globVar')):       # this seems to work
    print 'param =', param, 'globVar =', globVar  # display values

Або, якщо ви хочете бути в безпеці,

def func(param = None)):
    if param == None:
        param = globVar
    print 'param =', param, 'globVar =', globVar  # display values

Це нагадало мені про проблему призначення порожнього списку як значення за замовчуванням . І, як у прикладі, використовуйте isдля перевірки, чи є щось Noneзамість звичайного порівняння ==.
berna1111

6

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

var = 1
def global_var_change():
      global var
      var = "value changed"
global_var_change() #call the function for changes
print var

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


2

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

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


2
Таке формулювання прикро. У Python значення, присвоєне змінній, є посиланням, тому це технічно правильно (і я не сумніваюся, ви це мали на увазі), але багато читачів можуть інтерпретувати "змінити значення" як "мутувати об'єкт", що не є випадок - xs.append(xs.pop(0))працює чудово без цього global xs.

@delnan Моя відповідь ретельно сформульована, але я уточню.
Марцін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.