Переменная Python определяет объем ошибки

Предупреждение: невозможно изменить информацию заголовка - уже отправленные заголовки

Случается, когда ваш скрипт пытается отправить HTTP-клиенту клиенту, но он уже был выведен ранее, что привело к тому, что заголовки уже отправлены на клиент.

Это E_WARNING , и он не остановит сценарий.

Типичным примером может быть файл шаблона, подобный этому:


    
    My Page

...

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

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

Часто пропускаемый вывод - это новые строки после закрытия PHP ?>. Считается стандартной практикой опускать ?>, когда это последняя вещь в файле. Аналогичным образом, еще одной распространенной причиной этого предупреждения является то, что перед открытием перед ним появляется пустое пространство, строка или невидимый символ, в результате чего веб-сервер отправляет заголовки и пробел / новую строку, таким образом, когда PHP начинает синтаксический анализ, он не сможет для отправки любого заголовка.

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

Также убедитесь, что в вашем коде не указаны знаки байтового заказа, например, когда кодировка скрипта является UTF -8 с BOM.

Вопросы, относящиеся

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

8 ответов

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

, Если Вы хотите, чтобы переменная c относилась к глобальному c, помещает

global c

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

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

nonlocal c

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

204
ответ дан user2357112 supports Monica 23 November 2019 в 05:21
поделиться

Python является немного странным в этом, это сохраняет все в словаре для различных объемов. Оригинал a, b, c находятся в верхнем объеме и так в том верхнем словаре. Функция имеет свой собственный словарь. Когда Вы достигаете print(a) и print(b) операторы, нет ничего тем именем в словаре, таким образом, Python ищет список и находит их в глобальном словаре.

Теперь мы добираемся до c+=1, который, конечно, эквивалентен c=c+1. Когда Python сканирует ту строку, он говорит "ага, существует переменная, названная c, я помещу его в свой локальный словарь объема". Тогда, когда это идет, ища значение для c для c на правой стороне присвоения, это находит локальная переменная названный c, который еще не имеет никакого значения, и так бросает ошибку.

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

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

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

Обновление, см. комментарии:

Это не сканирует код дважды, но это действительно сканирует код в двух фазах, lexing и парсинге.

Рассматривают, как синтаксический анализ этой строки кода работает. Лексический анализатор читает исходный текст и повреждает его в лексемы, "самые маленькие компоненты" грамматики. Таким образом, когда это поражает строку

c+=1

, это разбивает его во что-то как [1 119]

SYMBOL(c) OPERATOR(+=) DIGIT(1)

, синтаксический анализатор в конечном счете хочет превратить это в дерево синтаксического анализа и выполнить его, но так как это - присвоение, прежде чем это сделает, это ищет имя c в локальном словаре, не видит его и вставляет его в словарь, отмечая его как неинициализированный. На полностью скомпилированном языке это просто вошло бы в таблицу символов и ожидало бы синтаксического анализа, но так как это не будет иметь роскоши второй передачи, лексический анализатор делает немного дополнительной работы для создания жизни легче позже. Только, тогда это видит ОПЕРАТОР, видит, что в правилах говорится, "если у Вас есть оператор + =, левая сторона, должно быть, была инициализирована" и говорит "возгласы!"

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

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

69
ответ дан Jonathan Leffler 23 November 2019 в 05:21
поделиться

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

>>> 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

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

43
ответ дан Brian 23 November 2019 в 05:21
поделиться

Python имеет довольно интересное поведение при попытке традиционной семантики глобальной переменной. Я не помню детали, но можно считать значение переменной, объявленной в 'глобальном' объеме очень хорошо, но если Вы хотите изменить его, необходимо использовать global ключевое слово. Попытайтесь измениться test() на это:

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

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

10
ответ дан Jonathan Leffler 23 November 2019 в 05:21
поделиться

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

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

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

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

a = a + b

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

a.__iadd__(b)

В первом случае (как долго как [1 111] не объявляется глобальным), вне локального объема нет никаких побочных эффектов, поскольку присвоение на [1 112] является просто обновлением указателя.

Во втором случае, a на самом деле изменит себя, таким образом, все ссылки на [1 114] укажут на измененную версию. Это продемонстрировано следующим кодом:

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

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

3
ответ дан Jonathan Leffler 23 November 2019 в 05:21
поделиться

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

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

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

2
ответ дан James Hopkin 23 November 2019 в 05:21
поделиться

Та же проблема беспокоит меня. Используя nonlocal и global может решить проблему.
Однако вниманию было нужно для использования nonlocal, оно работает на вложенные функции. Однако на уровне модуля, это не работает. См. примеры здесь.

0
ответ дан 23 November 2019 в 05:21
поделиться

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

1: docs.python .org / 3.1 / faq / programming.html? highlight = nonlocal # почему-я-получение-несвязанный-локальная ошибка-когда-переменная-имеет-значение

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

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

>>> 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
ответ дан 23 November 2019 в 05:21
поделиться
Другие вопросы по тегам:

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