Использование «глобального» ключевого слова в Python

285

Из прочтения документации я понимаю, что в Python есть отдельное пространство имен для функций, и если я хочу использовать глобальную переменную в этой функции, мне нужно ее использовать global.

Я использую Python 2.7, и я попробовал этот маленький тест

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

Кажется, все работает нормально, даже без global. Я смог получить доступ к глобальной переменной без каких-либо проблем.

Я что-то упустил? Кроме того, следующее из документации по Python:

Имена, перечисленные в глобальном операторе, не должны быть определены как формальные параметры или как цель управления циклом for, определение класса, определение функции или оператор импорта.

В то время как формальные параметры и определение класса имеют смысл для меня, я не могу понять ограничение для цели управления циклом и определения функции.

Nik
источник
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для объявления функций, классов или других объектов в локальном контексте. Хотя я бы посоветовал против этого, так как это вызывает кошмары, если что-то идет не так или требует отладки.

unode
источник
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

В этом разница между доступом к имени и привязке его в области видимости.

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

Однако если вы присваиваете переменную, имя которой не входит в локальную область, вы привязываете это имя к этой области (и если это имя также существует как глобальное, вы его скрываете).

Если вы хотите иметь возможность присваивать глобальное имя, вам нужно указать парсеру использовать глобальное имя, а не связывать новое локальное имя - это то, что делает ключевое слово «global».

Привязка в любом месте блока приводит к тому, что имя в этом блоке становится связанным, что может вызвать некоторые довольно странные последствия (например, 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
>>> 
pycruft
источник
очень нелогично, трудно поверить, что это правильный код Python
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 не прибегает к поиску имени как глобальной переменной, как это делают некоторые другие языки. По сути, вы не можете получить доступ к глобальной переменной, если вы определили локальную переменную с тем же именем в любом месте функции.

Kindall
источник
1
Спасибо за указание на это. Таким образом, до тех пор, пока ваша локальная область не присваивает имя, существующее за ее пределами, ссылки в локальной области будут использовать внешнее имя. Однако, если где-либо в вашей функции вы назначаете это имя, ссылки в этой локальной области, даже до локального назначения, не выглядят снаружи.
Дмитрий Минковский
1
Точно, у вас есть это. global(или nonlocalв Python 3.x) отменяет это поведение и позволяет переназначить внешнее имя.
любезно
2
На других языках это называется «подъем», например, так: github.com/shichuan/javascript-patterns/blob/master/…
Дмитрий Минковский
Чтобы добавить оскорбление ране, переменные, объявленные с более новым ключевым словом JavaScript let, не поднимаются.
любезно
Это быстрее для доступа к глобальной переменной, объявленной с 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
user225312
источник
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]
Martynas
источник
2

Предполагается, что любая переменная, объявленная вне функции, является глобальной, и только если вы объявляете их изнутри функций (кроме конструкторов), вы должны указать, что эта переменная будет глобальной.

Хесус Рамос
источник
1

Это хорошо объясняется в FAQ по 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

user7610
источник
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
источник
ikostia перечисляет все то, что вы не можете использовать 'x' для использования global - docs.python.org/reference/…
pycruft
1
@Unode: Я просто демонстрирую все случаи, которые NikhilRathod привел в своей цитате.
ikostia
0

Глобал делает переменную "Глобал"

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)
Майкл
источник