Документация по Python

Область видимости и привязка переменной

В: Документация по Python

Глобальные переменные

В Python переменные внутри функций считаются локальными тогда и только тогда, когда они появляются в левой части оператора присваивания или в каком-либо другом случае связывания; в противном случае такая привязка ищется во включающих функциях вплоть до глобальной области видимости. Это верно, даже если оператор присваивания никогда не выполняется.

x = 'Hi'

def read_x():
    print(x)   # x is just referenced, therefore assumed global

read_x()       # prints Hi

def read_y():
    print(y)   # here y is just referenced, therefore assumed global

read_y()       # NameError: global name 'y' is not defined

def read_y():
    y = 'Hey'  # y appears in an assignment, therefore it's local
    print(y)   # will find the local y

read_y()       # prints Hey

def read_x_local_fail():
    if False:
        x = 'Hey'  # x appears in an assignment, therefore it's local
    print(x)   # will look for the _local_ z, which is not assigned, and will not be found

read_x_local_fail()   # UnboundLocalError: local variable 'x' referenced before assignment

 

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

x = 'Hi'

def change_local_x():
    x = 'Bye'
    print(x)
change_local_x()  # prints Bye
print(x)  # prints Hi


 

Объявляя имя global означает , что, для остальной части сферы, любые присваивания имени будет происходить на верхнем уровне модуля:

x = 'Hi'

def change_global_x():
    global x
    x = 'Bye'
    print(x)

change_global_x()  # prints Bye
print(x)  # prints Bye

 

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

Подводя итог: для того , чтобы узнать , является ли переменным x является локальной для функции, вы должны прочитать всю функцию:

  1. если вы нашли global x , то x является глобальной переменной
  2. Если вы нашли nonlocal x , то x принадлежит к функции включения, и не является ни местным , ни глобальным
  3. Если вы нашли x = 5 или for x in range(3) или какой -либо другая привязка, то x является локальным переменным
  4. В противном случае x принадлежат некоторой области видимости (области видимости функции, глобальному охвату, или встроенным командам)

Локальные переменные

Если имя связывается внутри функции, то по умолчанию доступны только внутри функции:

def foo():
    a = 5
    print(a) # ok

print(a) #  NameError: name 'a' is not defined

 

Конструкции потока управления не оказывают никакого влияния на объем (за исключением except ), но доступ к переменной , которая еще не была назначена ошибка:

def foo():
    if True: 
        a = 5
    print(a) # ok

b = 3
def bar():
    if False:
        b = 5
    print(b) # UnboundLocalError: local variable 'b' referenced before assignment

 

Обычные связывающие операции задание, for петель и дополненные задания , таких как a += 5

Нелокальные переменные

Python 3 добавил новое ключевое слово под названием ** нелокальный **. Ключевое слово nonlocal добавляет переопределение области во внутреннюю область. Вы можете прочитать все об этом в [PEP 3104] [1]. Это лучше всего иллюстрируется парой примеров кода. Одним из наиболее распространенных примеров является создание функции, которая может увеличивать:

def counter():
    num = 0

    def incrementer():
        num + = 1
        return num

    return incrementer    	

Если вы попытаетесь запустить этот код, вы получите ** UnboundLocalError * * потому что на переменную ** num ** ссылаются до того, как она назначена в самой внутренней функции. Давайте добавим нелокальный в смесь:

def counter():
    num = 0
    def incrementer():
       nonlocal num
       num + = 1
       return num
    return incrementer

c = counter()
c() # = 1
c() # = 2
c() # = 3

По сути, `nonlocal` позволит вам назначать переменные во внешней области, но не в глобальной области. Таким образом, вы не можете использовать `nonlocal` в нашей функции` counter`, потому что тогда он попытается назначить глобальную область видимости. Попробуйте, и вы быстро получите `SyntaxError`. Вместо этого вы должны использовать `nonlocal` во вложенной функции. (Обратите внимание, что представленная здесь функциональность лучше реализована с использованием генераторов.)

Обязательное вхождение

x = 5
x += 7
for x in iterable: pass    

 

Каждый из приведенных выше утверждений является обязательным явлением - x стал привязано к объекту , обозначенному 5.Если это утверждение появляется внутри функции, то x будет функция локального по умолчанию. В разделе «Синтаксис» приведен список обязательных операторов.

Функции пропускают область видимости класса при поиске имен

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

a = 'global'

class Fred:
    a = 'class'  # class scope
    b = (a for i in range(10))  # function scope
    c = [a for i in range(10)]  # function scope
    d = a  # class scope
    e = lambda: a  # function scope
    f = lambda a=a: a  # default argument uses class scope

    @staticmethod  # or @classmethod, or regular instance method
    def g():  # function scope
        return a

print(Fred.a)  # class
print(next(Fred.b))  # global
print(Fred.c[0])  # class in Python 2, global in Python 3
print(Fred.d)  # class
print(Fred.e())  # global
print(Fred.f())  # class
print(Fred.g()) # global

 

Пользователи , не знакомые с тем, как эта сфера работы можно ожидать , b , c и e для печати class .

Из PEP 227 :

Из документации Пайтона на именования и связывания :

Область имен, определенных в блоке класса, ограничена блоком класса; он не распространяется на блоки кода методов - это включает в себя понимания и выражения генератора, поскольку они реализованы с использованием области действия функции. Это означает, что следующее не удастся:

class A:
    a = 42
    b = list(a + i for i in range(10)) 

В этом примере используются ссылки из этого ответа по Martijn Питерс, который содержит более глубокий анализ этого поведения.

Команда del

Эта команда имеет несколько связанных, но различных форм.

del v

Если v является переменной, команда del v удаляет переменную из ее сферы. Например:

x = 5
print(x) # out: 5
del x
print(x) # NameError: name 'f' is not defined
 

Обратите внимание , что del является обязательным вхождение, что означает , что , если явно не указано иное ( с использованием nonlocal или global ), del v сделает v локальными по отношению к текущей области. Если вы собираетесь удалить v во внешней области видимости, использовать nonlocal v или global v в том же объеме , в del v убытках.

Во всех следующих случаях намерение команды является поведением по умолчанию, но не поддерживается языком. Класс может быть написан таким способом, который лишает законной силы это намерение.

del v.name

Эта команда запускает вызов v.__delattr__(name) .

Намерение состоит в том, чтобы сделать атрибут name отсутствует. Например:

class A:
    pass

a = A()
a.x = 7
print(a.x) # out: 7
del a.x
print(a.x) # error: AttributeError: 'A' object has no attribute 'x'

 

del v[item]

Эта команда запускает вызов v.__delitem__(item) .

Намерение состоит в том, что item не будет принадлежать в отображении реализуемого объекта v.Например:

x = {'a': 1, 'b': 2}
del x['a']
print(x) #  out: {'b': 2}
print(x['a']) # error: KeyError: 'a'

 

del v[a:b]

Это на самом деле вызывает v.__delslice__(a, b) .

Намерение аналогично описанному выше, но с кусочками - диапазонами элементов вместо одного элемента. Например:

x = [0, 1, 2, 3, 4]
del x[1:3]
print(x) #  out: [0, 3, 4]

 

Смотрите также Garbage Collection # Команда дель .

Местный и глобальный охват

Каковы локальные и глобальные возможности?

Все variabes Python , которые доступны в какой - то момент в коде либо в локальной области видимости или в глобальном масштабе.

Объяснение состоит в том, что локальная область действия включает в себя все переменные, определенные в текущей функции, а глобальная область действия включает переменную d, определенную вне текущей функции.

foo = 1  # global

def func():
    bar = 2  # local
    print(foo)  # prints variable foo from global scope
    print(bar)  # prints variable bar from local scope

 

Можно проверить, какие переменные находятся в какой области. Встроенные функции locals() и globals() возвращают целые области как словари.

foo = 1

def func():
    bar = 2
    print(globals().keys())  # prints all variable names in global scope
    print(locals().keys())  # prints all variable names in local scope

 

Что происходит с конфликтами имен?

foo = 1

def func():
    foo = 2  # creates a new variable foo in local scope, global foo is not affected

    print(foo)  # prints 2

    # global variable foo still exists, unchanged:
    print(globals()['foo'])  # prints 1
    print(locals()['foo'])  # prints 2

 

Для того, чтобы изменить глобальную переменную, используйте ключевое слово global :

foo = 1

def func():
    global foo
    foo = 2  # this modifies the global foo, rather than creating a local variable


 

Область действия определяется для всего тела функции!

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

foo = 1

def func():
    # This function has a local variable foo, because it is defined down below.
    # So, foo is local from this point. Global foo is hidden.

    print(foo) # raises UnboundLocalError, because local foo is not yet initialized
    foo = 7
    print(foo)


 

Аналогично, опозит:

foo = 1

def func():
    # In this function, foo is a global variable from the begining

    foo = 7  # global foo is modified

    print(foo)  # 7
    print(globals()['foo'])  # 7

    global foo  # this could be anywhere within the function
    print(foo)  # 7

 

Функции внутри функций

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

foo = 1

def f1():
    bar = 1

    def f2():
        baz = 2
        # here, foo is a global variable, baz is a local variable
        # bar is not in either scope
        print(locals().keys())  # ['baz']
        print('bar' in locals())  # False
        print('bar' in globals())  # False

    def f3():
        baz = 3
        print(bar)  # bar from f1 is referenced so it enters local scope of f3 (closure)
        print(locals().keys())  # ['bar', 'baz']
        print('bar' in locals())  # True
        print('bar' in globals())  # False

    def f4():
        bar = 4  # a new local bar which hides bar from local scope of f1
        baz = 4
        print(bar)
        print(locals().keys())  # ['bar', 'baz']
        print('bar' in locals())  # True
        print('bar' in globals())  # False

 

Global против nonlocal (Python 3 только)

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

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

foo = 0  # global foo

def f1():
    foo = 1  # a new foo local in f1

    def f2():
        foo = 2  # a new foo local in f2

        def f3():
            foo = 3  # a new foo local in f3
            print(foo)  # 3
            foo = 30  # modifies local foo in f3 only

        def f4():
            global foo
            print(foo)  # 0
            foo = 100  # modifies global foo

 

С другой стороны, nonlocal, доступный в Python 3, принимает локальную переменную из охватывающей области в локальную область текущей функции.

Из документации Python на nonlocal :

Нелокальный оператор заставляет перечисленные идентификаторы ссылаться на ранее связанные переменные в ближайшей охватывающей области, исключая глобальные переменные.

def f1():
    
    def f2():
        foo = 2  # a new foo local in f2

        def f3():
            nonlocal foo  # foo from f2, which is the nearest enclosing scope
            print(foo)  # 2
            foo = 20  # modifies foo from f2!
Еще от кодкамп
Замечательно! Вы успешно подписались.
Добро пожаловать обратно! Вы успешно вошли
Вы успешно подписались на кодкамп.
Срок действия вашей ссылки истек.
Ура! Проверьте свою электронную почту на наличие волшебной ссылки для входа.
Успех! Ваша платежная информация обновлена.
Ваша платежная информация не была обновлена.