Ссылка перед назначением (вызов работает в непосредственном окне) [дубликат]

В соответствии с жизненным циклом MediaPlayer, который вы можете просмотреть в руководстве API Android , я думаю, что вы должны называть reset() вместо stop(), а после этого снова готовиться медиаплеер (используйте только один), чтобы воспроизвести звук с самого начала. Также учтите, что звук может закончиться. Поэтому я также рекомендую реализовать setOnCompletionListener(), чтобы убедиться, что если вы попытаетесь снова воспроизвести звук, он не сработает.

178
задан TankorSmash 30 May 2017 в 17:24
поделиться

11 ответов

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

Если вы хотите, чтобы переменная c ссылалась на глобальный c put

global c

в качестве первой строки функции.

Что касается python 3, теперь есть

nonlocal c

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

178
ответ дан user2357112 16 August 2018 в 02:02
поделиться
  • 1
    Благодарю. Быстрый вопрос. Означает ли это, что Python решает объем каждой переменной перед запуском программы? Перед запуском функции? – tba 16 December 2008 в 04:46
  • 2
    Решение переменной области принимается компилятором, который обычно запускается один раз при первом запуске программы. Однако стоит иметь в виду, что компилятор также может работать позже, если у вас есть & quot; eval & quot; или "exec" в вашей программе. – Greg Hewgill 16 December 2008 в 04:48
  • 3
    Хорошо, спасибо. Я предполагаю, что "интерпретируемый язык" не подразумевает столько, сколько я думал. – tba 16 December 2008 в 04:53
  • 4
    Ах, что «нелокальное» ключевое слово было именно тем, что я искал, казалось, что Python этого не видит. Предположительно, это «каскады» через каждую охватывающую область, которая импортирует переменную, используя это ключевое слово? – Brendan 17 November 2009 в 21:54
  • 5
    @brainfsck: проще всего понять, выполняете ли вы различие между "взглядом" и " и "назначение" Переменная. Поиск возвращается к более высокой области, если имя не найдено в текущей области. Назначение всегда выполняется в локальной области (если вы не используете global или nonlocal для принудительного глобального или нелокального назначения) – Steven 13 September 2011 в 13:00

Взгляд на разборку может прояснить, что происходит:

>>> def f():
...    print a
...    print b
...    a = 1

>>> import dis
>>> dis.dis(f)

  2           0 LOAD_FAST                0 (a)
              3 PRINT_ITEM
              4 PRINT_NEWLINE

  3           5 LOAD_GLOBAL              0 (b)
              8 PRINT_ITEM
              9 PRINT_NEWLINE

  4          10 LOAD_CONST               1 (1)
             13 STORE_FAST               0 (a)
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE

Как вы можете видеть, байт-код для доступа к a есть LOAD_FAST, а для b, LOAD_GLOBAL. Это связано с тем, что компилятор идентифицировал, что a назначается внутри функции, и классифицирует его как локальную переменную. Механизм доступа для местных жителей принципиально отличается для глобальных переменных - им статически присваивается смещение в таблице переменных фрейма, что означает, что поиск является быстрым индексом, а не более дорогим исканием dict, как для глобальных. Из-за этого Python считывает строку print a как «получает значение локальной переменной« a », содержащееся в слоте 0, и печатает его», и когда он обнаруживает, что эта переменная все еще не инициализирована, возникает исключение.

40
ответ дан Brian 16 August 2018 в 02:02
поделиться
  • 1
    Я раньше этого не видел. Интересные вещи - спасибо за это :-) – Jon Cage 16 December 2008 в 12:45
  • 2
    То же самое. Я должен посмотреть на это. – Charlie Martin 17 December 2008 в 03:47

c+=1 присваивает c, python предполагает, что назначенные переменные являются локальными, но в этом случае он не был объявлен локально.

Либо используйте ключевые слова global или nonlocal.

nonlocal работает только в python 3, поэтому, если вы используете python 2 и не хотите, чтобы ваша переменная была глобальной, вы можете использовать изменяемый объект:

my_variables = { # a mutable object
    'c': 3
}

def test():
    my_variables['c'] +=1

test()
2
ответ дан Colegram 16 August 2018 в 02:02
поделиться

Вот две ссылки, которые могут помочь

1: docs.python.org/3.1/faq/programming.html?highlight=nonlocal#why-am-i-getting-an- unboundlocalerror-when-the-variable-has-a-value

2: docs.python.org/3.1/faq/programming.html?highlight=nonlocal#how-do -i-write-a-function-with-output-parameters-call-by-reference

ссылка описывает ошибку UnboundLocalError. Ссылка 2 может помочь с повторной записью тестовой функции. На основе второй ссылки исходная проблема может быть переписана как:

>>> a, b, c = (1, 2, 3)
>>> print (a, b, c)
(1, 2, 3)
>>> def test (a, b, c):
...     print (a)
...     print (b)
...     print (c)
...     c += 1
...     return a, b, c
...
>>> a, b, c = test (a, b, c)
1
2
3
>>> print (a, b ,c)
(1, 2, 4)
5
ответ дан Daniel X Moore 16 August 2018 в 02:02
поделиться

Лучший способ получить переменную класса напрямую связан с именем класса

class Employee:
    counter=0

    def __init__(self):
        Employee.counter+=1
0
ответ дан Harun ERGUL 16 August 2018 в 02:02
поделиться

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

Как я уверен, вы уже знали, что имя, используемое слева от '=', неявно является локальной переменной. Не раз я был пойман, изменив переменный доступ к + =, и это неожиданно другая переменная.

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

2
ответ дан James Hopkin 16 August 2018 в 02:02
поделиться

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

В большинстве случаев вы склонны думать о расширенное присвоение (a += b) как точно эквивалентное простому присваиванию (a = a + b). С этим можно столкнуться, хотя в одном случае. Позвольте мне объяснить:

Путем простого задания Python означает, что если a передается в функцию (например, func(a), обратите внимание, что Python всегда передается по ссылке), тогда a = a + b не будет изменять переданный a. Вместо этого он просто изменит локальный указатель на a.

Но если вы используете a += b, то он иногда реализуется как:

a = a + b

или иногда (если существует метод) как:

a.__iadd__(b)

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

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

def copy_on_write(a):
      a = a + a
def inplace_add(a):
      a += a
a = [1]
copy_on_write(a)
print a # [1]
inplace_add(a)
print a # [1, 1]
b = 1
copy_on_write(b)
print b # [1]
inplace_add(b)
print b # 1

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

65
ответ дан Jonathan Leffler 16 August 2018 в 02:02
поделиться
  • 1
    Хорошо, спасибо за ваш ответ; он очистил некоторые вещи для меня о облаках в python. Тем не менее, я до сих пор не понимаю, почему ошибка возникает в строке (A), а не в строке (B). Создает ли Python свой словарь переменной scope перед запуском программы? – tba 16 December 2008 в 04:40
  • 2
    Спасибо за ваш ответ, но я не думаю, что это объясняет, почему ошибка возникает в строке (A), где я просто пытаюсь напечатать переменную. Программа никогда не попадает в строку (B), где она пытается изменить неинициализированную переменную. – tba 16 December 2008 в 04:42
  • 3
    Python будет читать, анализировать и превращать всю функцию во внутренний байт-код, прежде чем он начнет запускать программу, поэтому тот факт, что «превратить c в локальную переменную», происходит в текстовом режиме после того, как печать значения не как бы материальная. – Vatine 16 December 2008 в 11:10
  • 4
    Нет, это на уровне выражения. Я добавлю к ответу, я не думаю, что могу поместиться в комментарии. – Charlie Martin 16 December 2008 в 11:36
  • 5
    @CharlieMartin Хороший ответ и btw +1 для вашего комментария к профилю господина Мартина! сделал мой день: D – BugShotGG 1 October 2012 в 20:26
  • 6
    Замечание о деталях реализации. В CPython локальная область обычно не обрабатывается как dict, она внутренне только массив (locals() заполняет dict для возврата, но изменения в нем не создают новые locals). Фаза разбора находит каждое присваивание локальному и преобразует из имени в позицию в этом массиве и использует эту позицию всякий раз, когда имя ссылается. При входе в функцию локаторы без аргументов инициализируются в placeholder, а UnboundLocalError происходят, когда переменная читается, а связанный с ней индекс по-прежнему имеет значение-заполнитель. – ShadowRanger 25 March 2016 в 20:49

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

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

UnboundLocalError: локальная переменная 'c', на которую ссылаются перед присваиванием

. Решение для этого - использовать глобальную ключевое слово.

a, b, c = (1, 2, 3)

print(a, b, c)

def test():
    print(a)
    print(b)
    print(c)
    global c   # (A)
    c+=1       # (B)
test()

Если вы используете python 3, вы также можете использовать нелокальное ключевое слово

def test():
    print(a)
    print(b)
    print(c)
    ninlocal c # (A)
    c+=1       # (B)
test()
0
ответ дан Projesh Bhoumik 16 August 2018 в 02:02
поделиться

Лучший пример, который дает понять, это:

bar = 42
def foo():
    print bar
    if False:
        bar = 0

при вызове foo(), это также повышает UnboundLocalError, хотя мы никогда не достигнем строки bar=0, поэтому логически локальная переменная должна никогда не создаётся.

Тайна кроется в «Python - это интерпретируемый язык», и объявление функции foo интерпретируется как единый оператор (т. е. составной оператор), он просто интерпретирует его тупо и создает локальные и глобальные области. Таким образом, bar распознается в локальной области перед исполнением.

Для получения дополнительных примеров, таких как Читать это сообщение: http://blog.amir.rachum.com/blog/2013/07/09 / python-common-newbie-errors-part-2 /

В этом сообщении представлено полное описание и анализ области действия Python:

5
ответ дан Sahil kalra 16 August 2018 в 02:02
поделиться
66
ответ дан Jonathan Leffler 6 September 2018 в 01:18
поделиться
67
ответ дан Jonathan Leffler 29 October 2018 в 07:59
поделиться
Другие вопросы по тегам:

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