Почему нет там нет ++и --операторы в 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вообще неизменны. Буква intC просто обозначает место в памяти. И биты в этом месте очень изменчивы. Вы можете, например, создать ссылку 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()) :