Обзоры в Python для циклов

177

Я не спрашиваю о правилах Python; Я вообще понимаю, как работает цикл в Python для циклов. Мой вопрос, почему дизайнерские решения были приняты таким образом. Например (не каламбур):

for foo in xrange(10):
    bar = 2
print(foo, bar)

Выше будет напечатано (9,2).

Это кажется мне странным: 'foo' на самом деле просто контролирует цикл, а 'bar' был определен внутри цикла. Я могу понять, почему может быть необходимо, чтобы 'bar' был доступен вне цикла (в противном случае цикл имел бы очень ограниченную функциональность). Я не понимаю, почему управляющая переменная должна оставаться в области видимости после выхода из цикла. По моему опыту, это просто загромождает глобальное пространство имен и усложняет отслеживание ошибок, которые могут быть обнаружены переводчиками на других языках.

chimeracoder
источник
6
Если вы не хотите, чтобы forцикл загромождал ваше глобальное пространство имен, поместите его в функцию. Затворы в изобилии!
Ятанизм
24
Если вы не запускаете цикл в глобальном пространстве имен (необычно), он загромождает локальное пространство имен.
Гленн Мейнард
3
Если бы этого не было, как бы вы продолжили обработку позже в той точке, где остановились внутри цикла? Просто определить переменную управления перед циклом?
эндолит
9
@endolith Да ... Почему бы и не потребовать это?
Стивен Лу
3
ну, люди просто предпочтут то, что они привыкли делать. Я бы сказал, что подобные вещи наносят вред программисту Python, который привык к таким вещам и вынужден проходить болезненный процесс при переключении на другой язык. Для остальных из нас это аккуратный маленький ярлык, я полагаю.
Стивен Лу

Ответы:

107

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

Обновить

Вот хорошая дискуссия на эту тему: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

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

Короче говоря, вы можете винить в этом сообщество Python: P

Джереми Браун
источник
2
Как бы грамматика была более сложной, если бы область действия переменной индукции была ограничена телом цикла? Такое изменение будет ограничено семантическим анализом в Python, а не его грамматикой.
Чарльз
6
Циклы не являются блоками в Python. Такое изменение поведения потребовало бы либо фундаментального изменения грамматики, либо особого случая. Вся концепция индукционной переменной также не выражена в текущей грамматике. Грамматика предоставляет контракт о том, как переводчик будет интерпретировать. Я хочу сказать, что я не могу предвидеть, как можно изменить это поведение, не усложняя грамматику. Это все спорно , так как побочный эффект дизайнерского решения стал особенностью.
Джереми Браун
1
Этот пост здесь mail.python.org/pipermail/python-dev/2005-September/056677.html дает более подробную информацию о скорости и сложности, на которые ссылается мистер Браун.
Раджеш
62

Python не имеет блоков, как и некоторые другие языки (такие как C / C ++ или Java). Следовательно, область видимости в Python является функцией.

atzz
источник
3
Я в замешательстве - что мешает Python определять границы цикла так же, как функции?
химеракодер
36
Не совсем так, просто грамматика не сходила с ума. ( docs.python.org/reference/… ) "Блок - это фрагмент текста программы Python, который выполняется как единое целое. Ниже приведены блоки: модуль, тело функции и определение класса ..."
Джереми Браун
1
@ thebackhand, ничего. Это было просто признано ненужным.
habnabit
@ Джереми Браун - действительно. Хорошая заметка.
atzz
6
@thebackhand - в языках с блоками forциклы видимости являются естественным продолжением общего принципа. В Python это должен быть особый случай, и особых случаев следует избегать, если они не имеют убедительных преимуществ.
atzz
39

Действительно полезный случай для этого при использовании, enumerateи вы хотите, чтобы общее количество в конце:

for count, x in enumerate(someiterator, start=1):
    dosomething(count, x)
print "I did something {0} times".format(count)

Это необходимо? Нет, но это конечно удобно.

Еще одна вещь, о которой нужно знать: в Python 2 переменные в списках также просочились:

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9

Но то же самое не относится к Python 3.

деревенщина
источник
4
Вы могли бы сделать это, вероятно, в elseпункте, т.е. else: print "I did something {0} times".format(count)- до исчезновения локальной области видимости (которой нет в Python)
Nas Banov
3
Только второй пример не работает в Python 3, верно? Первый еще делает? Заметки о том, почему он был удален из Python 3?
эндолит
7
для подсчета, элемент в перечислении (a, start = 1): # индекс по умолчанию от нуля
Тао Чжан
3
Первый пример, а не хороший пример использования, больше напоминает доказательство того, что это правило определения области действия опасно и на него нельзя полагаться. Что если someiteratorпусто?
максимум
1
@Nas Хотя elseв этом случае можно использовать предложение, оно не будет работать вообще, так как тело цикла может breakпреждевременно.
Джеймсдлин
2

Если у вас есть оператор break в цикле (и вы хотите использовать значение итерации позже, возможно, чтобы выполнить резервное копирование, индексировать что-либо или присвоить статус), это сэкономит вам одну строку кода и одно присваивание, так что есть удобство.

макинтош
источник
1

Одним из основных факторов, влияющих на Python, является ABC , язык, разработанный в Нидерландах для обучения программированию концепций для начинающих. Создатель Python, Гвидо ван Россум, несколько лет работал над ABC в 1980-х годах. Я почти ничего не знаю о ABC, но так как он предназначен для начинающих, я полагаю, что он должен иметь ограниченное количество областей, так же, как ранние Бейсики.

Kindall
источник
-1

Для начала, если бы переменные были локальными для циклов, эти циклы были бы бесполезны для большинства реальных программ.

В текущей ситуации:

# Sum the values 0..9
total = 0
for foo in xrange(10):
    total = total + foo
print total

доходность 45. Теперь рассмотрим, как работает назначение в Python. Если переменные цикла были строго локальными:

# Sum the values 0..9?
total = 0
for foo in xrange(10):
    # Create a new integer object with value "total + foo" and bind it to a new
    # loop-local variable named "total".
    total = total + foo
print total

дает 0, потому что totalвнутри цикла после присваивания не та же переменная, что и totalвне цикла. Это не было бы оптимальным или ожидаемым поведением.

Кирк Штраузер
источник
5
Не отвечая на вопрос. ОП спрашивал о foo, а не total (или bar в их примере).
Джеймс Брэдбери
6
@JamesBradbury, totalи fooв сценарии ОП все равно будут локальные привязки петли, и логика та же.
Кирк Штраузер
2
ОП: «Я могу понять, почему может быть необходимо, чтобы« бар »был доступен вне цикла (в противном случае циклы имели бы очень ограниченную функциональность). Чего я не понимаю, так это того, почему необходимо, чтобы переменная управления оставалась после выхода из цикла. " (выделение мое)
Джеймс Брэдбери
2
@JamesBradbury Вы, возможно, правы, но я ответил на это три года назад, и, вероятно, сейчас не стоит обсуждать.
Кирк Штраузер