Почему нет там нет ++
и --
операторы в Python?
Почему нет там нет ++
и --
операторы в Python?
Ответы:
Это не потому, что это не имеет смысла; имеет смысл определить «x ++» как «x + = 1, оценивая предыдущую привязку x».
Если вы хотите узнать первоначальную причину, вам придется либо просмотреть старые списки рассылки Python, либо спросить кого-то, кто был там (например, Гвидо), но это достаточно легко обосновать после факта:
Простое увеличение и уменьшение не так много, как в других языках. Вы не for(int i = 0; i < 10; ++i)
часто пишете такие вещи, как на Python; вместо этого вы делаете вещи, как for i in range(0, 10)
.
Так как это не нужно почти так же часто, есть гораздо меньше причин для того, чтобы придать ему свой особый синтаксис; когда вам нужно увеличить, +=
обычно это нормально.
Это не решение того, имеет ли это смысл, или может ли это быть сделано - оно делает, и может. Вопрос в том, стоит ли добавлять это преимущество в основной синтаксис языка. Помните, что это четыре оператора - postinc, postdec, preinc, precc, и каждый из них должен иметь свои собственные перегрузки класса; все они должны быть указаны и протестированы; это добавило бы к языку операции коды (подразумевающие больший, и, следовательно, более медленный, механизм ВМ); каждый класс, который поддерживает логическое приращение, должен был бы реализовать их (сверху +=
и -=
).
Это все избыточно +=
и -=
, так что это станет чистым убытком.
i
напрямую - если вам это действительно нужно и не можете просто, например, использоватьarray.append()
i++
и ++i
...
++
и --
используемых способами, которые приводят к неопределенным или неопределенным поведение. Они позволяют писать сложный, трудный для правильного анализа код.
Этот оригинальный ответ, который я написал, является мифом из фольклора компьютерных технологий : Деннис Ритчи назвал его «исторически невозможным», как отмечается в письмах в редакцию журнала ACM, июль 2012 г., doi: 10.1145 / 2209249.2209251
Операторы инкремента / декремента C были изобретены в то время, когда компилятор C не был очень умным, и авторы хотели иметь возможность указать прямое намерение использовать оператор машинного языка, что позволило сэкономить несколько циклов для компилятора, который может сделать
load memory
load 1
add
store memory
вместо
inc memory
и PDP-11 даже поддерживает команды «автоинкремент» и «отложенный автоинкремент», соответствующие *++p
и *p++
, соответственно. Смотрите раздел 5.3 руководства, если вам интересно.
Поскольку компиляторы достаточно умны, чтобы справиться с высокоуровневыми приемами оптимизации, встроенными в синтаксис C, они теперь являются лишь синтаксическим удобством.
У Python нет трюков для передачи намерений ассемблеру, потому что он не использует их.
Я всегда предполагал, что это связано с этой строкой дзен питона:
Должен быть один - и желательно только один - очевидный способ сделать это.
x ++ и x + = 1 делают одно и то же, поэтому нет оснований для того и другого.
one--
это ноль?
one--
один в предложении, но сразу после этого ноль. Таким образом, этот «коан» также намекает на то, что операторы увеличения / уменьшения неочевидны.
Конечно, мы могли бы сказать: «Гвидо просто так решил», но я думаю, что вопрос действительно в причинах этого решения. Я думаю, что есть несколько причин:
Потому что в Python целые числа неизменны (int + = фактически возвращает другой объект).
Кроме того, с ++ / - вам нужно беспокоиться о предварительном увеличении / уменьшении, и для его написания требуется всего лишь еще одно нажатие клавиши x+=1
. Другими словами, это позволяет избежать потенциальной путаницы за счет очень небольшого выигрыша.
42++
... Что - то вроде этого (модифицирующую буквальная константы) был на самом деле возможно в некоторых старых Фортране (или так я прочитал): Все виды использования в будущем из этого литерала в этом прогоне программы будет действительно иметь другое значение. Удачной отладки!
int
вообще неизменны. Буква int
C просто обозначает место в памяти. И биты в этом месте очень изменчивы. Вы можете, например, создать ссылку int
и изменить референт этой ссылки. Это изменение видно во всех ссылках (включая исходную int
переменную) на это место. То же самое не относится к целочисленному объекту Python.
Python много говорит о ясности, и ни один программист, вероятно, не сможет правильно угадать значение, --a
если он не изучил язык с такой конструкцией.
В Python также много избегают конструкций, которые допускают ошибки, и ++
операторы, как известно, являются богатыми источниками дефектов. Этих двух причин недостаточно для того, чтобы в Python не было этих операторов.
Решение о том, что Python использует отступы для маркировки блоков, а не синтаксические средства, такие как некоторая форма начальных / конечных скобок или обязательная конечная маркировка, основано в основном на тех же соображениях.
Для иллюстрации взгляните на обсуждение вопроса о введении условного оператора (в C cond ? resultif : resultelse
:) в Python в 2005 году. Прочитайте, по крайней мере, первое сообщение и сообщение о решении этого обсуждения (в котором ранее было несколько предшественников по той же теме).
Общая информация: PEP, часто упоминаемый в этом документе, представляет собой «Предложение по расширению Python» PEP 308 . LC означает понимание списка , GE означает выражение генератора (и не волнуйтесь, если они вас смущают, это не одно из немногих сложных мест Python).
Мое понимание того, почему в python нет ++
оператора, заключается в следующем: когда вы пишете это в python, a=b=c=1
вы получите три переменные (метки), указывающие на один и тот же объект (значение которого равно 1). Вы можете проверить это с помощью функции id, которая будет возвращать адрес памяти объекта:
In [19]: id(a)
Out[19]: 34019256
In [20]: id(b)
Out[20]: 34019256
In [21]: id(c)
Out[21]: 34019256
Все три переменные (метки) указывают на один и тот же объект. Теперь увеличьте одну переменную и посмотрите, как она влияет на адреса памяти:
In [22] a = a + 1
In [23]: id(a)
Out[23]: 34019232
In [24]: id(b)
Out[24]: 34019256
In [25]: id(c)
Out[25]: 34019256
Вы можете видеть, что переменная a
теперь указывает на другой объект как переменные b
и c
. Потому что вы использовали a = a + 1
это явно ясно. Другими словами, вы назначаете совершенно другой объект для метки a
. Представьте, что вы можете написать, a++
это будет означать, что вы не присваиваете переменнуюa
новый объект, но, скорее всего, увеличиваете старый. Все это мелочи ИМХО для минимизации путаницы. Для лучшего понимания посмотрите, как работают переменные Python:
Является ли Python вызовом по значению или вызовом по ссылке? Ни.
Python передает по значению или по ссылке?
Является ли Python передачей по ссылке или передачей по значению?
Python: как передать переменную по ссылке?
Понимание переменных Python и управления памятью
Эмуляция поведения передачи по значению в Python
Это было разработано именно так. Операторы увеличения и уменьшения - просто ярлыки для x = x + 1
. Python обычно принимает стратегию проектирования, которая уменьшает количество альтернативных способов выполнения операции. Дополненное присваивание - самая близкая вещь к операторам увеличения / уменьшения в Python, и они даже не были добавлены до Python 2.0.
return a[i++]
на return a[i=i+1]
.
Я очень плохо знаком с Python, но подозреваю, что причина в том, что в языке делается акцент на изменяемые и неизменяемые объекты. Теперь, я знаю , что х ++ легко можно интерпретировать как х = х + 1, но это выглядит , как вы приращение на месте объекта , который может быть неизменен.
Просто мое предположение / чувство / догадка.
x++
ближе к x += 1
чем x = x + 1
, эти два также имеют значение для изменяемых объектов.
Во-первых, Python только косвенно зависит от C; он сильно подвержен влиянию ABC , у которого, по- видимому, нет этих операторов , поэтому неудивительно, что они не найдены в Python.
Во-вторых, как уже говорили другие, увеличение и уменьшение поддерживаются +=
и -=
уже.
В-третьих, полная поддержка набора операторов ++
и --
операторов обычно включает в себя поддержку их префиксной и постфиксной версий. В C и C ++ это может привести ко всем видам «прекрасных» конструкций, которые, как мне кажется, противоречат духу простоты и прямолинейности, который охватывает Python.
Например, хотя оператор C while(*t++ = *s++);
может показаться простым и элегантным опытному программисту, для кого-то, кто его изучает, это совсем не просто. Добавьте смесь префиксов и постфиксных приращений и уменьшений, и даже многим профессионалам придется остановиться и задуматься.
Я считаю, что это вытекает из убеждения Python, что «явное лучше, чем неявное».
Это может быть из-за того, что @GlennMaynard смотрит на этот вопрос по сравнению с другими языками, но в Python вы делаете все по-Питонски. Это не вопрос «почему». Это там, и вы можете делать вещи с тем же эффектом x+=
. В дзен Python сказано: «должен быть только один способ решить проблему». Многочисленные варианты хороши в искусстве (свобода выражения мнений), но отвратительны в технике.
++
Класс операторов выражение с побочными эффектами. Это то, чего обычно нет в Python.
По той же причине присваивание не является выражением в Python, что препятствует распространению if (a = f(...)) { /* using a here */ }
идиомы.
Наконец, я подозреваю, что там операторы не очень согласуются с семантикой ссылок Pythons. Помните, что в Python нет переменных (или указателей) с семантикой, известной из C / C ++.
f(a)
где a
список, какой-то неизменный объект.
Возможно, лучше задать вопрос: почему эти операторы существуют в C. Операции приращения и убывания вызовов K & R «необычны» (Раздел 2.8, стр. 46). Введение называет их «более краткими и зачастую более эффективными». Я подозреваю, что тот факт, что эти операции всегда возникают при манипуляции с указателями, также сыграл свою роль в их введении. В Python, вероятно, было решено, что нет смысла пытаться оптимизировать приращения (на самом деле я только что провел тест на C, и кажется, что сгенерированная gcc сборка использует addl вместо incl в обоих случаях) и нет арифметика указателей; так что это был бы просто еще один способ сделать это, и мы знаем, что Python ненавидит это.
как я понял, вы не будете думать, что значение в памяти изменилось. в c, когда вы делаете x ++, значение x в памяти изменяется. но в python все числа неизменны, поэтому адрес, на который указывает x, все еще имеет x, а не x + 1. когда вы пишете x ++, вы можете подумать, что x изменит то, что действительно происходит, так это то, что x refrence заменяется местом в памяти, где хранится x + 1, или воссоздаете это место, если doe не существует.
++
отличается += 1
?
Чтобы завершить уже хорошие ответы на этой странице:
Давайте предположим, что мы решили сделать это, префикс (++i
), который сломал бы унарные операторы + и -.
Сегодня, префикс ++
или --
ничего не делает, потому что он включает унарный оператор плюс дважды (ничего не делает) или унарный минус дважды (дважды: отменяет себя)
>>> i=12
>>> ++i
12
>>> --i
12
Так что это может нарушить эту логику.
В других ответах описано, почему это не нужно для итераторов, но иногда это полезно при назначении для увеличения переменной в строке, вы можете добиться того же эффекта, используя кортежи и множественное присваивание:
b = ++a
будет выглядеть так:
a,b = (a+1,)*2
и b = a++
становится:
a,b = a+1, a
Python 3.8 вводит задание :=
оператора, что позволяет нам достичь foo(++a)
с
foo(a:=a+1)
foo(a++)
все еще неуловимо все же.
Я думаю, что это относится к понятиям изменчивости и неизменности объектов. 2,3,4,5 неизменны в питоне. Обратитесь к изображению ниже. 2 имеет фиксированный идентификатор до этого процесса Python.
x ++ по существу означал бы приращение на месте, подобное C. В C x ++ выполняет приращения на месте. Таким образом, x = 3, а x ++ увеличивает значение 3 в памяти до 4, в отличие от python, где 3 все еще существует в памяти.
Таким образом, в python вам не нужно воссоздавать значение в памяти. Это может привести к оптимизации производительности.
Это ответ на догадку.
Я знаю, что это старый поток, но наиболее распространенный вариант использования для ++ i не рассматривается, это ручная индексация наборов, когда нет предоставленных индексов. Именно поэтому Python предоставляет enumerate ()
Пример: в любом конкретном языке, когда вы используете конструкцию наподобие foreach для итерации по набору - в качестве примера мы даже скажем, что это неупорядоченный набор, и вам нужен уникальный индекс для всего, чтобы отличить их, скажем,
i = 0
stuff = {'a': 'b', 'c': 'd', 'e': 'f'}
uniquestuff = {}
for key, val in stuff.items() :
uniquestuff[key] = '{0}{1}'.format(val, i)
i += 1
В подобных случаях python предоставляет метод перечисления, например
for i, (key, val) in enumerate(stuff.items()) :