Використання "глобального" ключового слова в Python


285

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

Я використовую Python 2.7, і я спробував цей невеликий тест

>>> sub = ['0', '0', '0', '0']
>>> def getJoin():
...     return '.'.join(sub)
...
>>> getJoin()
'0.0.0.0'

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

Я щось пропускаю? Також з документації Python:

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

Хоча формальні параметри та визначення класу мають сенс для мене, я не в змозі зрозуміти обмеження на визначення цілі та визначення функції циклу.


1
Я думаю, що вас плутають з php, який вимагає використання глобального ключового слова - документи python це підтверджують - в основному, якщо це не визначено в локальному контексті, це трактується як глобальний
tobyodavies

11
Будьте обережні зі своїм формулюванням: Python не має окремого простору імен для функцій (це означає, що ви могли б мати def foo(): ...і foo = ...одночасно). Це створює нову область для кожного виклику функції. (Але чим це відрізняється від будь-якої іншої мови віддаленого високого рівня у світі?)

Відповіді:


366

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

def bob():
    me = "locally defined"    # Defined only in local context
    print(me)

bob()
print(me)     # Asking for a global variable

Наведене вище:

locally defined
Traceback (most recent call last):
  File "file.py", line 9, in <module>
    print(me)
NameError: name 'me' is not defined

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

def bob():
    global me
    me = "locally defined"   # Defined locally but declared as global
    print(me)

bob()
print(me)     # Asking for a global variable

Отже, наведений вище код дасть вам:

locally defined
locally defined

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


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

17
@juice - У Python немає такого поняття, як абсолютний globalsавтоматично визначений у всіх просторах імен (на щастя). Як ви правильно вказали, глобальний зв'язок пов'язаний з простором імен в модулі, однак його можна імпортувати в інший модуль як from module import variableабо import module.variable. У першому випадку імпорт зробить змінну доступною як, variableне вимагаючи посилання як module.. Якщо він вважатиметься глобальним, обсяг модуля буде залежати від того, куди він імпортується. Дивіться також nonlocalяк нове ключове слово, пов’язане з сферою дії, у python 3.
unode

3
Чи можете ви пояснити, чому глобальні змінні не є хорошим рішенням? Я часто це чую, але в моєму теперішньому проекті вони, здається, роблять саме те, що мені потрібно. Чи є щось більш зловісне, про що я не думав?
Робін Ньюхаус

5
@RobinNewhouse Є кілька запитань щодо SO, які вже висвітлюють цю тему та інші статті, що не стосуються SO .
unode

213

Хоча ви можете отримати доступ до глобальних змінних без globalключового слова, якщо ви хочете змінити їх, ви повинні використовувати globalключове слово. Наприклад:

foo = 1
def test():
    foo = 2 # new local foo

def blub():
    global foo
    foo = 3 # changes the value of the global foo

У вашому випадку ви просто отримуєте доступ до списку sub.


3
З одним застереженням: foo = 3без глобальних робіт, але foo знову визначається локально в області blubфункцій і не змінює оригінальну змінну foo. Це мене дуже заплутало.
chhantyal

1
@chhantyal, якщо під творами ви розумієте, що це не призводить до помилок, ви маєте рацію, але в контексті Іво Ветцеля він би не працював так, як задумано. Для такої поведінки є використання, але часто це не те, що хоче програміст.
демоцидист

77

Це різниця між доступом до імені та прив'язкою до нього в межах сфери.

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

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

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

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

>>> a = 1
>>> def p():
    print(a) # accessing global scope, no binding going on
>>> def q():
    a = 3 # binding a name in local scope - hiding global
    print(a)
>>> def r():
    print(a) # fail - a is bound to local scope, but not assigned yet
    a = 4
>>> p()
1
>>> q()
3
>>> r()
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    r()
  File "<pyshell#32>", line 2, in r
    print(a) # fail - a is bound to local scope, but not assigned yet
UnboundLocalError: local variable 'a' referenced before assignment
>>> 

дуже протизаконний, важко повірити, що це дійсний код пітона
PlsWork

52

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

Розглянемо це, наприклад:

value = 42

def doit():
    print value
    value = 0

doit()
print value

Ви, напевно, можете здогадатися, що value = 0оператор буде призначати локальну змінну і не впливатиме на значення тієї самої змінної, оголошеної поза doit()функцією. Ви можете бути більш здивовані, дізнавшись, що наведений вище код не працюватиме. Оператор print valueвсередині функції виробляєUnboundLocalError.

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


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

1
Точно, у вас це вийшло. global(або nonlocalв Python 3.x) переосмислює таку поведінку і дозволяє повторно призначити зовнішнє ім'я.
kindall

2
В інших мовах це, мабуть, називається "підйомним", наприклад, наприклад: github.com/shichuan/javascript-patterns/blob/master/…
Дмитро Мінковський

Щоб додати образи до травми, змінні, задекларовані за допомогою нового ключового слова JavaScript let, не містяться .
kindall

Чи швидше отримати доступ до глобальної змінної, оголошеної за допомогою, globalабо це не має значення?
мато

14

Доступ до імені та присвоєння імені різні. У вашому випадку ви просто отримуєте доступ до імені.

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

>>> x = 1         # global 
>>> def foo():
        print x       # accessing it, it is global

>>> foo()
1
>>> def foo():   
        x = 2        # local x
        print x 

>>> x            # global x
1
>>> foo()        # prints local x
2

7
  • Ви можете отримати доступ до глобальних ключових слів без ключового слова global
  • Щоб мати змогу змінити їх, вам потрібно чітко вказати, що ключове слово є глобальним. В іншому випадку ключове слово буде оголошено в локальному масштабі.

Приклад:

words = [...] 

def contains (word): 
    global words             # <- not really needed
    return (word in words) 

def add (word): 
    global words             # must specify that we're working with a global keyword
    if word not in words: 
        words += [word]

2

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


1

Це добре пояснено у поширених питаннях Python

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

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

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

https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python


0

Це означає, що ви не повинні робити наступне:

x = 1

def myfunc():
  global x

  # formal parameter
  def localfunction(x):
    return x+1

  # import statement
  import os.path as x

  # for loop control target
  for x in range(10):
    print x

  # class definition
  class x(object):
    def __init__(self):
      pass

  #function definition
  def x():
    print "I'm bad"

ikostia перераховує всі речі, які ви не можете використати "x" для використання глобальних - docs.python.org/reference/…
pycruft

1
@Unode: Я просто демонструю всі випадки, про які розповів NikhilRathod у своїй цитаті.
ikostia

0

Global робить змінну "Global"

def out():
    global x
    x = 1
    print(x)
    return


out()

print (x)

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

def out():
     # Taking out the global will give you an error since the variable x is no longer 'global' or in other words: accessible for other commands
    x = 1
    print(x)
    return


out()

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