Python: Почему глобальный нужен только для присваивания, а не для чтения?

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

<code>X = 10
def foo():
    global X
    X = 20 # Needs global declaration
def bar():
    print( X ) # Does not need global
</code>

Мой вопрос касается дизайна Python: почему Python предназначен для чтения глобальных переменных без использования глобального объявления? То есть, почему только принудительное присвоение должно иметь глобальное значение, почему не принудительное глобальное при чтении тоже? (Это сделало бы это даже и изящным.)

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

 Inverse03 мая 2012 г., 23:26
Чтобы скрыть тонкие ошибки?

Ответы на вопрос(4)

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

Один из вариантов (возможно, фактически используемый гораздо более старыми версиями Python, IIRC) - просто сказать, что запись всегда идет в локальную область. Тогда нет необходимости вglobal ключевое слово, и нет двусмысленности. Но тогда вы вообще не можете писать в глобальные переменные (не используя такие вещи, какglobals() чтобы добраться до них в обход), так что это не будет здорово.

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

Другой вариант будет иметьx = 3 присваивать локальной переменной только в том случае, если в какой-то внешней области с именем еще нет имениx, Похоже, это интуитивно сделает правильную вещь? Это может привести к серьезным неприятным случаям. В настоящее время, гдеx = 3 запись в статически определяется парсером; либо нетglobal x в том же объеме, и это локальная запись, или естьglobal x и это глобальная запись. Но если то, что он будет делать, зависит от глобальной области видимости модуля, вам придется подождать до времени выполнения, чтобы обнаружить, и узнать, куда идет записьwhich means it can change between invocations of a function, Подумай об этом. Каждый раз, когда вы создаете глобал в модуле, вы изменяете поведение всех функций в модуле, которые используют это имя в качестве имени локальной переменной. Выполните некоторое вычисление области видимости модуля, которое используетtmp в качестве временной переменной и попрощаться с использованиемtmp вall функции в модуле. И мне не терпится подумать о неясных ошибках, связанных с назначением атрибута импортированному вами модулю и последующим вызовом функции из этого модуля.Yuck.

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

Существует неопределенность с назначениями, для решения которой необходим какой-то механизм.global является одним из таких механизмов. Это не единственно возможный вариант, но в контексте Python все альтернативные механизмы ужасны. Я не знаю, какая "лучшая причина" Вы ищете.

 28 апр. 2012 г., 08:10
@Ashwin Глобальная область не отличается от любой другой области. Нет единого статического объявления того, что оно содержит; Python просто выполняет код в модуле, в результате чего имена назначаются в глобальной области видимости. Это точно так же, как имена определяются в локальной области видимости. Кроме того, любой другой код со ссылкой на модуль (после его импорта) может присваивать ему атрибуты, а атрибуты модуля - это просто глобальные переменные внутри этого модуля. Плюс функции в модуле можно использоватьglobal, Это то, на что вы ссылаетесь?
 Ashwin Nanjappa28 апр. 2012 г., 07:37
Бен: новичок Python здесь. Можно ли «ввести»? новая глобальная переменная во время выполнения, кроме тех, которые уже перечислены в исходном коде в глобальной области видимости? Ваши ответы, кажется, указывают на это, я хотел бы знать, как это возможно.
 Ashwin Nanjappa04 мая 2012 г., 05:04
Бен: Понял. Спасибо :-)
Решение Вопроса

Посмотрите на этот код:

from module import function

def foo(x):
    return function(x)

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

Прежде чем сказать, что вашX и мойfunction различаются (поскольку одно является переменной, а другое является импортированной функцией), помните, что все имена в Python обрабатываются одинаково: при использовании их значение ищется в иерархии области действия. Если вам нужноglobal X тогда вам нужноglobal function, Ик.

 28 апр. 2012 г., 05:53
На самом деле, это название вопроса. Настоящий вопрос:why is Python designed to allow the read of global variables without using the global declaration, but not modify?
 Ashwin Nanjappa28 апр. 2012 г., 07:29
Предро: Нед отвечает на мой настоящий вопрос. Прошу прощения, если я перепутал читателей с моим английским. Я тоже исправил текст вопроса.
 28 апр. 2012 г., 05:26
@jterrace: вопрос был "зачем нужен глобальныйonly в командировке?, & quot; нет, & quot; почему глобально требуется при назначении. & quot;
 28 апр. 2012 г., 05:19
Это действительно не отвечает на вопрос, хотя. Вы можете распространить этот аргумент и на изменение глобальных переменных. Почему явный глобал для модификации глобалов?
 28 апр. 2012 г., 05:20
Потому что, если вы не включитеglobal X заявлениеX = 10 создаст местныйX связан с10 вместо того, чтобы привязать глобальныйX в10.

Потому что явное лучше, чем неявное.

Нет никакой двусмысленности, когда вы читаете переменную. Вы всегда получаете первый найденный при поиске областей от локальных до глобальных.

Когда вы назначаете, интерпретатор может только однозначно предположить, что вы назначаете, только две области: локальная и глобальная. Поскольку присвоение локальному является наиболее распространенным случаем, а присвоение глобальному фактически не рекомендуется, это значение по умолчанию. Чтобы назначить глобальное, вы должны сделать это явно, сообщая интерпретатору, что где бы вы ни использовали эту переменную в этой области, она должна переходить прямо в глобальную область, и вы будете знать, что делаете. В Python 3 вы также можете назначить ближайшую включающую область с помощью «нелокальный».

Помните, что когда вы присваиваете имя в Python, это новое назначение не имеет ничего общего с тем именем, ранее существовавшим для чего-то другого. Представьте, что по умолчанию не установлено значение local, и Python выполнил поиск во всех областях, пытаясь найти переменную с этим именем и присвоить ей то же, что и при чтении. Ваши функции & apos; поведение может меняться не только в зависимости от ваших параметров, но и от объема, в котором они находятся. Жизнь была бы несчастна.

 Ashwin Nanjappa28 апр. 2012 г., 07:33
Педро: Если вы пишете простой скрипт, функция которого должна изменять глобальное состояние, что вы делаете? Что если классы слишком тяжелы для простого сценария?
 28 апр. 2012 г., 05:45
В качестве дополнительного примечания, которое не очень подходит для ответа, я профессионально программирую на Python в течение 8 лет, и яnever использовал глобальный для чего-либо.

С вложенными областями поиск переменных легко. Они встречаются в цепочке, начиная с локальных, заканчивая defs, глобалами модулей и затем встроенными. Правило - первое найденное совпадение. Соответственно, вам не нужен "глобальный" статус. декларация для поиска.

Напротив, с записями вам нужно указать, в какую область писать. В противном случае невозможно определить, является ли "x = 10" Функция in будет означать «запись в локальное пространство имен». или & quot; запись в глобальное пространство имен. & quot;

Резюме, с write у вас есть выбор пространства имен, но при поиске достаточно первого найденного правила. Надеюсь это поможет :-)

Изменить: Да, это так "потому что BDFL сказал", но в других языках без объявлений типов нет ничего необычного в том, чтобы иметь правило первого поиска для поисков и требовать только модификатор для нелокальных записей. Когда вы думаете об этом, эти два правила приводят к очень чистому коду, так как модификаторы области нужны только в наименьшем общем случае (нелокальные записи).

 28 апр. 2012 г., 05:57
+1 за LEGB, мне всегда было легко запомнить

Ваш ответ на вопрос