Подтвердить что ты не робот

Python: Почему глобально необходимо только при назначении, а не на чтениях?

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

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

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

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

4b9b3361

Ответ 1

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

from module import function

def foo(x):
    return function(x)

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

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

Ответ 2

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

В отличие от записи, вам нужно указать, к какой области писать. В противном случае нет способа определить, будет ли "x = 10" в функции означать "писать в локальное пространство имен" или "писать в глобальное пространство имен".

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Другой вариант заключается в том, чтобы x = 3 назначать локальную переменную только в том случае, если в какой-либо внешней области имени уже нет имени с именем x. Похоже, это будет интуитивно делать правильные вещи? Тем не менее, это привело бы к серьезным неприятным ситуациям с углами. В настоящее время, где x = 3 будет писать, статически определяется парсером; либо там нет global x в той же области видимости, и это локальная запись, либо есть global x, и это глобальная запись. Но если то, что он будет делать, зависит от области глобального модуля, вам нужно подождать до тех пор, пока среда выполнения не определит, где идет запись , что означает, что она может изменяться между вызовами функции. Подумай об этом. Каждый раз, когда вы создаете глобальный модуль, вы должны изменять поведение всех функций в модуле, который использовал это имя в качестве имени локальной переменной. Проведите некоторое вычисление области модуля, которое использует tmp как временную переменную и попрощается использовать tmp в всех в модуле. И я содрогаюсь, чтобы подумать о неясных ошибках, связанных с назначением атрибута на импортированном модуле, а затем вызовом функции из этого модуля. Тьфу.

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


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