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

Введение

Примеры

  • 2

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

    В 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 принадлежат некоторой области видимости (области видимости функции, глобальному охвату, или встроенным командам)
  • 1

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

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

     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

  • 3

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

    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 (): нелокальный num num + = 1 return num return incrementer c = counter () c () # = 1 c () # = 2 c () # = 3 По сути, `nonlocal` позволит вам назначать переменные во внешней области, но не в глобальной области. Таким образом, вы не можете использовать `nonlocal` в нашей функции` counter`, потому что тогда он попытается назначить глобальную область видимости. Попробуйте, и вы быстро получите `SyntaxError`. Вместо этого вы должны использовать `nonlocal` во вложенной функции. (Обратите внимание, что представленная здесь функциональность лучше реализована с использованием генераторов.)
  • 0

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

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

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

  • 0

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

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

     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 Питерс, который содержит более глубокий анализ этого поведения.

  • 0

    Команда 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 # Команда дель .

  • 0

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

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

    Все 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 (см https://codecamp.ru/documentation/python/263/variable-scope-and-binding/5712/nonlocal-variables#t=201609030858342242664 ), доступный в Python 3, принимает локальную переменную из охватывающей области в локальную область текущей функции.

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

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

    def f1 (): def f2 (): foo = 2 # новый локальный foo в f2 def f3 (): нелокальный foo # foo из f2, который является ближайшей включающей областью печати (foo) # 2 foo = 20 # изменяет foo от f2!

Синтаксис

Параметры

Примечания