Понимание списка Python с фиктивными именами, идентичными имени итератора: опрометчиво?

Скажем, я создаю понимание списка, которое выглядит примерно так:

i = range(5)
a = [f(i) for i in i]

для некоторой функции f. Будет ли использование фиктивного имени, идентичного итератору, когда-либо приводить к неожиданным результатам? Иногда у меня есть имена переменных, которые представляют собой отдельные буквы, и для меня удобнее придерживаться одной и той же буквы, а не назначать новую, например [f(x) for x in x] вместо [f(i) for i in x] (например, если буква итератора x имеет смысл, мне будет интересно, что, черт возьми, такое i).


person Luke Davis    schedule 01.05.2017    source источник
comment
Плохой совет, хотя бы по какой-либо другой причине, потому что это чертовски сбивает с толку человека, читающего код.   -  person Fred Larson    schedule 01.05.2017
comment
А как насчет [f(x) for x in X]?   -  person Elmex80s    schedule 01.05.2017
comment
Как чтение [f(x) for x in x] более читабельно, чем [f(i) for i in x]? Здесь x изначально является списком, а i (в вашем более позднем примере) является элементом списка. Второй более читабелен. Как удобнее назвать список и элемент списка одной и той же переменной?   -  person Anonymous    schedule 01.05.2017
comment
А как насчет map(), как в map(f,i)?   -  person arshajii    schedule 01.05.2017
comment
Я думаю, вы можете получить неожиданные результаты, если будете использовать вложенные итерации, но если есть только один оператор for, вам может быть это сойдет с рук. При этом пожалуйста, не делайте этого.   -  person juanpa.arrivillaga    schedule 01.05.2017
comment
Хотя это может иметь смысл для вас, я уверен, что это сбивает с толку большинство людей, которые видят. Я рекомендую придерживаться разных имен переменных, как сказал @FredLarson.   -  person Christian Dean    schedule 01.05.2017
comment
Или просто [f(_) for _ in i]. Если вам не хочется создавать имя для переменной, которую вы будете использовать только один раз или не будете использовать вообще, просто назовите ее _, т. е. здесь ничего важного, пожалуйста, продолжайте.   -  person ForceBru    schedule 01.05.2017
comment
@ForceBru ооо... Мне действительно это нравится. Мне не нравится присваивать фиктивным переменным случайные буквы, потому что односимвольное имя итератора часто имеет смысл.   -  person Luke Davis    schedule 01.05.2017
comment
В какой-то момент вы попытаетесь использовать имя i для ссылки на итерируемый объект вместо элемента, и вы потратите часы, задаваясь вопросом, почему что-то не работает, и злитесь на Python. Или, может быть, вам нужно запустить что-то на Python 2, и вы будете смущены и поражены, когда значение i за пределами понимания изменится после завершения понимания.   -  person user2357112 supports Monica    schedule 01.05.2017
comment
Я настоятельно рекомендую использовать однобуквенные переменные только для идиоматического использования: for k, v in dct:. Переменные должны быть различны. Можете ли вы сделать вещи супер запутанными, перегружая переменные? Да. Тебе следует? Нет. Это действительный Py3, который решает проблему и [намеренно] почти нечитаем: print(['no','yes'][any([_ for _ in[([_ for _ in _ if _ in"aeiou"],print("{} has {} vowel(s).".format(_,len([_ for _ in _ if _ in"aeiou"]))))for _ in wordlist[::3]]if len(_[False])>=3])]). См. repl.it.   -  person TemporalWolf    schedule 01.05.2017
comment
Я очень удивлен, узнав, что этот вопрос получил 7 голосов!   -  person Elmex80s    schedule 02.05.2017
comment
@ Elmex80s Я тоже, если честно.   -  person Luke Davis    schedule 02.05.2017


Ответы (2)


TL;DR: Технически это безопасно, но стилистически плохой выбор.

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

Поэтому в теле «цикла» понимания списка (которое фактически создает область видимости в Python 3) вы можете повторно привязать имя, которое изначально указывало на итерируемый объект, без каких-либо последствий. Итерация имеет дело со ссылкой на итератор напрямую, и не имеет значения, есть ли у него имя в области видимости. То же самое должно быть верно и в Python 2, хотя детали реализации области видимости другие: имя коллекции будет потеряно после понимания, так как имя переменной цикла останется привязанным к последнему элементу итерации.

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

[f(x) for x in xs]
person wim    schedule 01.05.2017
comment
В Python 2 вещи (обычно) не ломаются в самом понимании, но они ломаются, как только что-то пытается использовать i после понимания, поскольку понимание топталось по исходному значению i. - person user2357112 supports Monica; 01.05.2017
comment
Ага. Добавлено предупреждение об ошибке утечки области видимости в Python 2. - person wim; 02.05.2017
comment
Хорошая работа по изложению технических причин, по которым этот сейф. - person Christian Dean; 02.05.2017
comment
Безопасно в том смысле, что безопасно стрелять в себя из незаряженного ружья, или безопасно протыкать стол между пальцами, или жонглировать обезвреженной взрывчаткой безопасно - может быть, если вы не сделаете никаких ошибок, это не будет ужасно неправильно, но вы нарушаете все правила безопасности, и вы должны винить только себя, когда неизбежно возникают проблемы. - person user2357112 supports Monica; 02.05.2017
comment
@ user2357112 Думаю, вы неправильно поняли смысл моего комментария. Когда я сказал, что Вим хорошо показал технические причины безопасности, я имел в виду то, как он объяснил, как Python генерирует и выполняет определенные коды операций. Мне это показалось интересным, и я сообщил ему, как хорошо он показал, что происходит за кулисами. Я однако не говорил, что эта практика безопасна. Это очень плохая идея, которая может привести к многочисленным головным болям. - person Christian Dean; 02.05.2017

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

Однако это приводит к гораздо более важному моменту. Зачем вообще использовать такие имена, как i, j или x? Использование однобуквенных имен переменных вызывает путаницу и неоднозначно. Вместо этого используйте имя переменной, которое четко передает ваши намерения.

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

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

Потому что, в конце концов, вы бы предпочли поддерживать такой код

[str(x) for x in x]

или это?

[str(user_id) for user_id in user_ids]
person Christian Dean    schedule 01.05.2017
comment
Насколько я могу судить, вы можете вкладывать без проблем, а не должны. - person TemporalWolf; 02.05.2017
comment
@TemporalWolf Спасибо, я учту это в своем ответе. - person Christian Dean; 02.05.2017
comment
Кроме того, если вы предпочитаете использовать отладку pdb.set_trace(), однобуквенные переменные часто сталкиваются с конфликтами имен с командами pdb. - person JL Peyret; 02.05.2017