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

Почему назначение Python не возвращает значение?

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

Например:

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

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

lst.append(x = X())

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

4b9b3361

Ответ 1

Есть много людей, которые считают, что присвоения являются выражениями, особенно в таких языках, как 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 является локальным из-за назначения. Это может быть еще более запутанным (чем это уже есть), если бы можно было похоронить назначение внутри некоторого более крупного выражения/утверждения.

Ответ 2

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

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

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

Аналогично для записи многих циклов:

while(i++ < 10)
    ;

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

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

Ответ 3

Выражения присвоения (sub-) (x := y) поддерживаются начиная с Python 3.8 (выпущено в октябре 2019 г.), так что теперь вы действительно можете переписать свой пример как lst.append(x := X()).

Предложение, PEP 572, было официально принято Гвидо в июле 2018 года. Ранее были также предложения по выражениям уступки, такие как отозванный PEP 379.

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

Оператор x = y = z для назначения одного и того же значения нескольким целям (или, скорее, нескольким целевым спискам, поскольку распаковка также разрешена) уже поддерживается (например, начиная с версии 1), но реализован в виде специального синтаксиса а не путем цепочки последовательных выражений присваивания sub-. Действительно, порядок выполнения отдельных назначений меняется на противоположный: вложенные моржи (x := (y := z)) должны назначить y до x, тогда как x = y = z назначает x до y (что может быть уместно, если вы установить/присвоить индексам или атрибутам класса, который был перегружен для создания некоторого побочного эффекта).

Ответ 4

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

if x = 3: print x

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

if x == 3: ...

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

Ответ 5

  • Синтаксис Python гораздо менее подробный, чем синтаксис C.
  • Он имеет гораздо более сложные правила области, чем C.
  • Использование круглых скобок в каждом отдельном выражении уменьшает читаемость кода, а python избегает этого.

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

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

а не

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

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

Ответ 6

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

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

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

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

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

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

Мир.


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 также является языком сценариев, но стал намного больше. В другими словами, он кажется более случайным, чем продуманный дизайн. Надеюсь, это не то, что люди имеют в виду, когда говорят о pythonicity.

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

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

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

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

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