Почему присвоение Python не возвращает значение? - PullRequest
41 голосов
/ 02 февраля 2011

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

Например:

# lst is some sequence
# X is come class
x = X()
lst.append(x)

можно было бы переписать как:

lst.append(x = X())

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

Ответы [ 6 ]

41 голосов
/ 02 февраля 2011

Многие считают, что присвоения могут быть выражениями, особенно в таких языках, как Python, где любое значение допустимо в условии (а не только значения некоторого логического типа) и подвержено ошибкам.Предположительно, Гвидо был / был среди тех, кто так считает.Классическая ошибка:

if x = y: # oops! meant to say ==

Ситуация также немного сложнее в Python, чем в языке, подобном C, поскольку в Python первое присваивание переменной также является ее объявлением.Например:

def f():
    print x

def g():
    x = h()
    print x

В этих двух функциях строки "print x" выполняют разные функции: одна относится к глобальной переменной x, а другая относится к локальной переменной x.x в g является локальным из-за назначения.Это могло бы быть еще более запутанным (чем это уже есть), если бы было возможно скрыть присваивание внутри более крупного выражения / оператора.

15 голосов
/ 03 февраля 2011

Реальный ответ: он не нужен.

В большинстве случаев вы видите это в C из-за того, что обработка ошибок выполняется вручную:

if((fd = open("file", O_RDONLY)) == -1)
{
    // error handling
}

Аналогичноза то, как написано много циклов:

while(i++ < 10)
    ;

Эти общие случаи в Python выполняются по-разному.Обработка ошибок обычно использует обработку исключений;Циклы обычно используют итераторы.

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

7 голосов
/ 03 июля 2018

Можно ожидать, что поддержка (x := y) выражений будет реализована в ближайшей версии Python.Гвидо недавно принял предложение PEP 572 в июле 2018 года о поддержке выражений присваивания в python.(Ранее были также предложения, такие как отозванный PEP 379 .)

Напомним, что до версии 3 print также являлось утверждением, а не выражением.

Примечание: Оператор x = y = z для назначения одного и того же значения нескольким целям (или, скорее, нескольким target-lists , поскольку распаковка также разрешена) уже давно поддерживаетсяв Python, но реализован в виде специального синтаксиса , а не путем объединения последовательных подвыражений присваивания.(Действительно, порядок выполнения отдельных назначений меняется на противоположный ..)

7 голосов
/ 02 февраля 2011

Я считаю, что это было преднамеренным со стороны Гвидо, чтобы предотвратить некоторые классические ошибки. Э.Г.

if x = 3: print x

когда вы на самом деле хотели сказать

if x == 3: ...

Я согласен, что бывали моменты, когда я хотел, чтобы это работало, но я также пропускаю { и } вокруг блока кода, и это точно не изменится.

4 голосов
/ 02 февраля 2011
  1. Синтаксис Python гораздо менее многословен, чем синтаксис C.
  2. У него гораздо более сложные правила области видимости, чем у C.
  3. Использование скобок в каждом отдельном выражении снижает читабельность кода, а python избегает этого.

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

if a and (h not in b): ...

, а не

if (a && !(h in b)) { ... }

[речь не идет о классической (если a = b :) разновидности ошибки.]

0 голосов
/ 18 февраля 2013

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

Вне более общих принципов, моя предпочтительная практическая причина иметь назначение - выражениедолжен иметь читаемый эквивалент оператора case, когда я хочу сопоставить строку с несколькими шаблонами (извлечение под-шаблонов), пока один из них не завершится успешно.Может быть, у кого-то есть хорошее решение, которого я не видел.

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

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

Илюди, которые хотят использовать присваивание в качестве выражений, просто скажут так.

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

Peace.


Post-sriptum - Это добавляется после того, как первые пять абзацев раздела 1 в обсуждении ниже были опубликованы.

Я не знаю, почему разработчики Python сделали такой выбор.Избегание общепризнанной ошибки if a=b : ... вместо if a==b : ... вряд ли является оправданием.

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

Во-вторых, та же проблема допускается в другом контексте.Можно написать a = b=c, имея в виду на самом деле написать a = b==c, что совсем другое.И ошибка не так заметна, когда b и c являются большими выражениями.Кроме того, хотя это, вероятно, было бы обнаружено как ошибка типа, если бы язык был статически типизирован, это не так в динамически типизированном языке, таком как Python (это действительно верно для = против == во всех контекстах).

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

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

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

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

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

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

Есть ли письменное обоснование для Python, которое документирует выбор дизайна в целом и обсуждаемую здесь проблему, в частности?

...