Пространство имен переменных в Python для цикла [duplicate]

Вот забавный ответ.

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

На самом деле я не могу претендовать на кредит для этого. Это была рекомендация IntelliJ! Чувствует себя немного взломанным. Но это не так плохо, как глобальная переменная, поэтому я думал, что стоит упомянуть здесь. Пожалуйста, не голосуйте за мой ответ, если вы не согласны! Это просто решение проблемы. Не обязательно лучший.

final int[] tapCount = {0};

addSiteButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
       tapCount[0]++;
    }

});
396
задан martineau 23 April 2017 в 03:10
поделиться

7 ответов

Python решает ваши переменные с - вообще - тремя доступными пространствами имен.

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

Существуют две функции: globals и locals, которые показывают вам содержимое двух из этих пространств имен.

Пространства имен создаются пакетами, модулями, классами, конструкцией объектов и функциями. Других ароматов пространств имен нет.

В этом случае вызов функции с именем x должен быть разрешен в локальном пространстве имен или в глобальном пространстве имен.

Локальный в этом случае является телом функция метода Foo.spam.

Глобальный - это хорошо глобальный.

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

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

Внутри определения класса имена являются частью пространства имен классов. code2, например, должно быть квалифицировано именем класса. Обычно Foo.code2. Тем не менее, self.code2 также будет работать, потому что объекты Python смотрят на содержащийся класс как на обратную сторону.

Объект (экземпляр класса) имеет переменные экземпляра. Эти имена находятся в пространстве имен объекта. Они должны быть квалифицированы объектом. (variable.instance.)

Из метода класса вы имеете локальные и глобальные переменные. Вы говорите self.variable, чтобы выбрать экземпляр как пространство имен. Вы заметите, что self является аргументом для каждой функции-члена класса, делая его частью локального пространства имен.

См. Правила области Python , Область Python , Диапазон переменных .

354
ответ дан Community 19 August 2018 в 20:01
поделиться
  • 1
    Это устарело. Начиная с версии 2.1 (7 лет назад) существует более двух областей, так как вложенные функции вводят новые области видимости, поэтому функция внутри функции будет иметь доступ к ее локальной области видимости, охватывающей области функций и глобальной области (также встроенным). – Brian 15 November 2008 в 22:24
  • 2
    Извините, это уже не так. Python has two namespaces available. Global and local-to-something. – Rizwan Kassim 16 November 2008 в 01:56
  • 3
    U не охватывал область действия code2. Это не переменная и является атрибутом class / instance. Это правильно. – Lakshman Prasad 5 June 2009 в 13:39
  • 4
    моя интуиция говорит, что code2 существует внутри области класса Foo и может быть доступен из любой области с доступом к Foo с Foo.code2 или изнутри Foo с тем же синтаксисом. Но я еще не уверен, где это входит в мнемонику LEGB. – Conrad.Dean 24 March 2012 в 17:51
  • 5
    Как предостережение к глобальному доступу - чтение глобальной переменной может произойти без явного объявления, но запись в него без объявления global (var_name) вместо этого создаст новый локальный экземпляр. – Peter Gibson 27 June 2012 в 06:53
  • 6
    Фактически @Peter, global(var_name) синтаксически неверен. Правильный синтаксис будет global var_name без круглых скобок. Однако у вас есть действительная точка. – martineau 24 December 2012 в 23:48
  • 7
    @Jonathan: Поскольку каждый y записывается и нет объявлений global y - см. Комментарий @ Peter. – martineau 6 August 2013 в 20:19
358
ответ дан Community 31 October 2018 в 05:55
поделиться

Не было никакого тщательного ответа относительно времени Python3, поэтому я сделал здесь ответ.

Как указано в других ответах, есть четыре основных области, LEGB, для Local, Enclosing, Global и Builtin. В дополнение к этим, существует особая область, тело класса, которая не содержит охватывающей области для методов, определенных внутри класса; любые присваивания внутри тела класса делают переменную оттуда связанной с телом в классе.

В частности, никакой блок-оператор, кроме def и class, не создает область переменной. В Python 2 понимание списка не создает область переменной, однако в Python 3 переменная цикла создается в новой области.

Чтобы продемонстрировать особенности тела класса

x = 0
class X(object):
    y = x
    x = x + 1 # x is now a variable 
    z = x

    def method(self):
        print(self.x) # -> 1
        print(x)      # -> 0, the global x
        print(y)      # -> NameError: global name 'y' is not defined

inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)

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


. Одна из больших неожиданностей для многих новичков на Python заключается в том, что цикл for не создает область переменной. В Python 2 представления в списках не создают области (как в случае генераторов, так и в выражениях dict)! Вместо этого они пропускают значение в функции или глобальной области:

>>> [ i for i in range(5) ]
>>> i
4

. Понимание может быть использовано как коварный (или ужасный, если хотите) способ сделать изменяемые переменные в лямбда-выражениях в Python 2 - выражение лямбда создает переменную область видимости, как и оператор def, но в пределах лямбда никаких утверждений не допускается. Назначение, являющееся выражением в Python, означает, что никакие назначения переменных в лямбда не разрешены, но понимание списка является выражением ...

Это поведение было исправлено в Python 3 - нет выражений понимания или переменных утечки генераторов.


Глобальное действительно означает область модуля; основным модулем python является __main__; все импортированные модули доступны через переменную sys.modules; для доступа к __main__ можно использовать sys.modules['__main__'] или import __main__; вполне приемлемо для доступа и назначения атрибутов; они будут отображаться как переменные в глобальной области основного модуля.


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

x = 5
def foobar():
    print(x)  # causes UnboundLocalError!
    x += 1    # because assignment here makes x a local variable within the function

# call the function
foobar()

scope может объявить, что он явно хочет изменить глобальную (область видимости модуля) с глобальным ключевым словом:

x = 5
def foobar():
    global x
    print(x) # -> 5
    x += 1

foobar()
print(x) # -> 6

Это также возможно, даже если оно было затенено в охватывающей области:

x = 5
y = 13
def make_closure():
    x = 42
    y = 911
    def func():
        global x # sees the global value
        print(x, y)
        x += 1

    return func

func = make_closure()
func()      # -> print 5 911
print(x, y) # -> 6 13

В python 2 нет простого способа изменить значение в охватывающей области; обычно это моделируется с помощью изменяемого значения, такого как список с длиной 1:

def make_closure():
    value = [0]
    def get_next_value():
        value[0] += 1
        return value[0]

    return get_next_value

get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2

Однако в python 3 nonlocal приходит на помощь:

def make_closure():
    value = 0
    def get_next_value():
        nonlocal value
        value += 1
        return value
    return get_next_value

get_next = make_closure() # identical behavior to the previous example.
< hr>

Любая переменная, которая не считается локальной для текущей области или любой охватывающей области, является глобальной переменной. Глобальное имя просматривается в глобальном словаре модуля; если он не найден, глобальный отображается с модуля встроенных модулей; имя модуля было изменено с python 2 на python 3; в python 2 это было __builtin__, а в python 3 теперь называется builtins. Если вы назначаете атрибут встроенного модуля, после этого он будет отображаться в любом модуле как читаемая глобальная переменная, если только этот модуль не тени их собственной глобальной переменной с тем же именем.


Чтение встроенный модуль также может быть полезен; предположим, что вы хотите использовать функцию печати в стиле python 3 в некоторых частях файла, но в других частях файла по-прежнему используется оператор print, если ваша версия python равна> = 2.6, вы можете получить новую функцию стиля как:

import __builtin__

print3 = __builtin__.__dict__['print']

На самом деле from __future__ import print_function не импортирует функцию print в любом месте Python 2, вместо этого он просто отключает правила синтаксического анализа для оператора print в текущем модуле, обрабатывая print, как и любую другую переменную Идентификатор и, таким образом, позволяет print искать функцию во встроенных функциях.

83
ответ дан Antti Haapala 19 August 2018 в 20:01
поделиться
  • 1
    @pindakaas, вы ошибаетесь, это действительно сработало, но в выдержке отсутствовал вызов функции и одна половина двоеточия. – Antti Haapala 22 May 2018 в 08:32
  • 2
    Хорошо, теперь это несколько правильно. благодаря – pindakaas 22 May 2018 в 08:49
  • 3
    @pindakaas, если вы думаете, что что-то неясно, тогда это может быть абзац текста раньше. Код верный и о том, что я хочу продемонстрировать. – Antti Haapala 22 May 2018 в 08:50

Где x найдено?

x не найден, так как вы его не определили. :-) Его можно найти в code1 (global) или code3 (local), если вы его поместили.

code2 (члены класса) не видны для кода внутри методов одного и того же класса - вы бы обычно получают доступ к ним, используя себя. code4 / code5 (петли) живут в той же области, что и для кода3, поэтому, если вы написали на x, вы бы изменили экземпляр x, определенный в коде3, не создавая новый x.

Python статически охвачен , поэтому, если вы передадите «спам» другой функции, спам по-прежнему будет иметь доступ к глобальным переменным в модуле, из которого он пришел (определен в коде1), и в любых других областях (см. ниже). члены code2 будут снова доступны через self.

lambda ничем не отличается от def. Если у вас есть лямбда, используемая внутри функции, это то же самое, что и определение вложенной функции. В Python 2.2 и далее доступны вложенные области. В этом случае вы можете связывать x на любом уровне вложенности функций, а Python будет извлекать самый внутренний экземпляр:

x= 0
def fun1():
    x= 1
    def fun2():
        x= 2
        def fun3():
            return x
        return fun3()
    return fun2()
print fun1(), x

2 0

fun3 видит экземпляр x из ближайшей содержащей области, которая является областью функции, связанной с fun2. Но другие x-экземпляры, определенные в fun1 и глобально, не затрагиваются.

До nested_scopes - в Python pre-2.1 и в 2.1, если вы специально не запрашиваете эту функцию с использованием from-future-import - fun1 и fun2 не видны fun3, поэтому ответ S.Lott имеет место, и вы получите глобальный x:

0 0
7
ответ дан bobince 19 August 2018 в 20:01
поделиться

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

В вашем Например, есть только 3 области, где x будет искать в:

  • области спама - содержащем все, что определено в code3 и code5 (а также code4, ваша переменная цикла)
  • Глобальная область - содержащая все, что определено в коде1, а также Foo (и любые изменения после него)
  • Пространство имен builtins. Немного специального случая - это содержит различные встроенные функции и типы Python, такие как len () и str (). Как правило, это не должно изменяться никаким кодом пользователя, поэтому ожидайте, что он будет содержать стандартные функции и ничего больше.

Больше областей появляется только при введении вложенной функции (или лямбда) в изображение. Они будут вести себя так, как вы ожидали. Вложенная функция может получить доступ ко всем в локальной области, а также к любой области приложения. например,

def foo():
    x=4
    def bar():
        print x  # Accesses x from foo's scope
    bar()  # Prints 4
    x=5
    bar()  # Prints 5

Ограничения:

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

global_var1 = []
global_var2 = 1

def func():
    # This is OK: It's just accessing, not rebinding
    global_var1.append(4) 

    # This won't affect global_var2. Instead it creates a new variable
    global_var2 = 2 

    local1 = 4
    def embedded_func():
        # Again, this doen't affect func's local1 variable.  It creates a 
        # new local variable also called local1 instead.
        local1 = 5
        print local1

    embedded_func() # Prints 5
    print local1    # Prints 4

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

global_var = 4
def change_global():
    global global_var
    global_var = global_var + 1

В настоящее время нет способа сделать то же самое для переменных в приложении областей function , но Python 3 вводит новое ключевое слово «nonlocal», которое будет действуют аналогично глобальным, но для вложенных областей функций.

136
ответ дан Brian 19 August 2018 в 20:01
поделиться

Правила обзора для Python 2.x уже изложены в других ответах. Единственное, что я хотел бы добавить, это то, что в Python 3.0 существует также концепция нелокальной области (обозначается ключевым словом «нелокальное»).

EDIT: Здесь PEP .

EDIT: здесь PEP ] с дополнительной информацией об этом.

20
ответ дан Jeremy Cantrell 19 August 2018 в 20:01
поделиться

Немного более полный пример области:

from __future__ import print_function  # for python 2 support

x = 100
print("1. Global x:", x)
class Test(object):
    y = x
    print("2. Enclosed y:", y)
    x = x + 1
    print("3. Enclosed x:", x)

    def method(self):
        print("4. Enclosed self.x", self.x)
        print("5. Global x", x)
        try:
            print(y)
        except NameError as e:
            print("6.", e)

    def method_local_ref(self):
        try:
            print(x)
        except UnboundLocalError as e:
            print("7.", e)
        x = 200 # causing 7 because has same name
        print("8. Local x", x)

inst = Test()
inst.method()
inst.method_local_ref()
Выход

:

1. Global x: 100
2. Enclosed y: 100
3. Enclosed x: 101
4. Enclosed self.x 101
5. Global x 100
6. global name 'y' is not defined
7. local variable 'x' referenced before assignment
8. Local x 200
18
ответ дан martineau 19 August 2018 в 20:01
поделиться
  • 1
    Это отличный ответ. Однако я считаю, что различия между method и method_local_ref должны быть выделены. method может получить доступ к глобальной переменной и распечатать ее, как в 5. Global x. Но method_local_ref не может, потому что позже он определяет локальную переменную с тем же именем. Вы можете проверить это, удалив строку x = 200 и увидите разницу – kiril 9 September 2016 в 10:35
  • 2
    @brianray: А как насчет z? – Malik A. Rumi 27 August 2017 в 03:40
  • 3
    @kiril Я добавил примечание об этом – brianray 15 November 2017 в 01:15
  • 4
    @ MalikA.Rumi Я удалил z, поскольку это не было интересно – brianray 15 November 2017 в 01:15
  • 5
    – not2qubit 7 October 2018 в 15:50
Другие вопросы по тегам:

Похожие вопросы: