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

Использование операторов с обеих сторон тернарной переменной python

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

>>> x, y = 0, 0
>>> (x += 1) if random.choice([0, 1]) else (y += 1)
        ^
SyntaxError: invalid syntax

>>> (x if random.choice([0, 1]) else y) += 1
SyntaxError: can't assign to conditional expression


>>> print 'hello world' if random.choice([0, 1]) else raise StandardError()
  File "<stdin>", line 1
    print 'hello world' if random.choice([0, 1]) else raise StandardError()
                                                          ^
SyntaxError: invalid syntax

Можете ли вы привести пример, где разрешение оператора, которое будет использоваться в тройном, может быть опасным или неопределенным?

4b9b3361

Ответ 1

Выражения eval uated, утверждения exec uted. Это нечто совершенно другое.

Разработчики Python решили строго разделить выражения и выражения. Это заставит вас "свалиться раньше", а не заканчивать ошибкой, которую трудно отладить.

В других языках, таких как C (++), вы можете делать такие вещи, как

if (i=15) {...}

но вы также можете сделать

if (i==15) {...}

В первом примере вы назначаете 15 переменной i, а это новое значение i затем оценивается с помощью if.

Хуже действуют операторы increment/decment. В чем разница между

if (i--) {...}

и

if (--i) {...}

?

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

В Python такие вещи запрещены синтаксисом из-за опыта, накопленного с такими понятиями на других языках.

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

Ответ 2

Это не имеет ничего общего с условными выражениями 1. Программы Python состоят из операторов. Большинство частей большинства выражений являются выражениями. Выражения содержат только другие выражения.

y += 1 - это оператор и не допускается, когда ожидается выражение. Тройной условный как целое является выражением, и каждая из трех его частей является выражением. Нет больше причин допускать (x += 1) if random.choice([0, 1]) else (y += 1), чем допускать любое из следующих чудовищ:

x = (y += 1)
def foo(x=(x += 1)):
    print x
print [x += 1, x *= 10]

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

x = y + pass
[return True, import sys]

Ничто из этого не имеет никакого смысла. Также не существует (x += 1) if random.choice([0, 1]) else (y += 1), потому что все точки условных выражений должны быть выражениями. Таким образом, это было бы более реалистично отображаться в заявлении, например:

z = (x += 1) if random.choice([0, 1]) else (y += 1)

Можно предположить, что "значение" x += 1 - это значение x (до или после добавления 1), как это делает C. Но это значительно усложняет язык. И это еще не решает проблему:

z = pass if (import sys) else (while False: print 17)

Каково значение pass? Из import sys? Из цикла while?

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

Простой факт: если вы пытаетесь записать это как один оператор:

(x += 1) if random.choice([0, 1]) else (y += 1)

Тогда у Python уже есть синтаксис для выражения этой идеи, и именно это:

if random.choice([0, 1]):
    x += 1
else:
    y += 1

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


1 Назовите это "тернарным условным", если вам нужно, но "тройной" или "тройной оператор" просто глупый. То, что у него есть 3 операнда, вряд ли самое главное в этом; что как вызов + "двоичного оператора".

Ответ 3

Первый синтаксис

Ваш первый синтаксис действительно является традиционным if statement, который вы пытались записать в одной строке с условием, а первое действие было отменено, Это слишком сложно использовать однострочные конструкции таким образом, и это уродливо и нечитаемо. Python не является C.

Второй синтаксис

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

В Python все ссылается, а lvalue позволяет изменить то, на что ссылается ссылка, но rvalue не работает.

Пример:

a = 5 # here a is lvalue
b = a + 1 # here a is rvalue and b is lvalue

Другим примером rvalue -одно выражений являются константы. С точки зрения интерпретатора ваша вторая попытка выглядит так же, как

42 = 42 + 1 # WHAT THE HECK!?

Почему

Что касается того, почему было решено сделать условное выражение свободным от утверждений (кричит, похоже, что мы уже нашли причину!): as PEP 308, условное выражение было первоначально введено для использования, а не с ошибкой x and y or z boolean expression, которое работало одинаково из-за short-circuit оценка.

Если Python должен был разрешить statements как ваш в условных выражениях, тогда он должен был разрешить, например, raise. Это считается плохим стилем кода Python, который заполняет много логики в однострочном (как я уже сказал выше).

Посмотрите на это

result = some_long_name / some_other_name if some_other_name != 0 else raise ZeroDivisionError

Он выглядит как выражение в начале, но затем он ведет себя как оператор и даже вызывает исключения!:( Принимая во внимание рекомендацию Python, чтобы стричь строки на 79 символов, вы даже не увидели бы raise в, скажем, многооконном бок о бок.


Ответ 4

Какую версию python вы используете? Этот синтаксис не поддерживается в python 2.4 atleast.. для меня работали на python 3.3. В боковом узле удалите paranthesis:

import random
x,y=0,0
x += 1 if random.choice([0,1]) else (y +1)