Чому в Python немає ++ і - операторів?


442

Чому немає там немає ++і --оператори в Python?


1
Повідомлення, пов’язані з цим - Поведінка операторів приросту та зменшення в Python
RBT

бо там зайве
cmarangu

Є 4 різних ++ операторів, які роблять те саме. Ну і там видалення "++" з "C ++" тепер, що здається переродженням
cmarangu

Відповіді:


443

Це не тому, що це не має сенсу; має сенс визначити "x ++" як "x + = 1, оцінюючи попереднє прив'язування x".

Якщо ви хочете дізнатися первісну причину, вам доведеться пройтись через старі списки розсилки Python або запитати когось, хто там був (наприклад, Guido), але це досить просто виправдати після факту:

Простий приріст і декремент не потрібні настільки, як в інших мовах. Ви не пишете речі, як for(int i = 0; i < 10; ++i)у Python, дуже часто; натомість ви робите подібні речі for i in range(0, 10).

Оскільки це не потрібно майже так часто, є набагато менше причин надати йому свій особливий синтаксис; коли вам потрібно приріст, +=зазвичай це просто добре.

Це не рішення, чи має це сенс, чи це можна зробити - це і може. Це питання, чи варто користь додавати до основного синтаксису мови. Пам'ятайте, що це чотири оператори - postinc, postdec, preinc, predec, і кожен з них повинен мати власні перевантаження класу; всі вони повинні бути уточнені та протестовані; це додало б мовних опкодів (маючи на увазі більшу і, отже, більш повільну, двигун VM); кожен клас, який підтримує логічний приріст, повинен був би їх реалізувати (поверх +=та -=).

Це все зайве +=і -=, таким чином, це стане чистим збитком.


98
Часто корисно використовувати щось на зразок масиву [i ++], що не впорядковано з + = / - =.
Тернер Хейс

102
@thayes: Це не звичайна модель в Python.
Гленн Мейнард

9
@thayes Оскільки це буде всередині циклу, ви могли б також перебираємо iбезпосередньо - якщо ви на самому справі потрібно, і може не тільки , наприклад , використанняarray.append()
Tobias Kienzler

31
Я бачу набагато більшу стурбованість читання та передбачуваність. Ще в мої C дні я побачив більш ніж достатньо помилок, що виникають із непорозумінь щодо різниці між i++та ++i...
Чарльз Даффі

5
На додаток до виправдання факту: над проектом, над яким я працюю, я зіткнувся (більше, ніж хто повинен у своєму житті) неабияку кількість коду С ++, який страждає від проблем ++і --використовується таким чином, що призводить до невизначеності чи не визначеності поведінка. Вони дозволяють писати складний, важко правильний для розбору код.
Брайан Ванденберг

84

Ця оригінальна відповідь, яку я написав, є міфом з фольклору обчислень : Деніс Рітчі розвінчаний як "історично неможливий", як зазначено в листах до редакцій " Комунікацій ОСББ" липня 2012 року : 10.1145 / 2209249.2209251


Оператори збільшення / зменшення С були винайдені в той час, коли компілятор С був не дуже розумним, і автори хотіли мати можливість вказати прямий намір використовувати машинний оператор мови, який зберігав кілька компіляторів для компілятора, який може зробити

load memory
load 1
add
store memory

замість

inc memory 

і PDP-11 навіть підтримує інструкції "автопосилення" та "відкладені автопосилення", що відповідають *++p і *p++відповідно. Дивіться розділ 5.3 цього посібника, якщо це жахливо цікаво.

Оскільки компілятори досить розумні, щоб керувати хитрощами оптимізації високого рівня, вбудованими в синтаксис C, вони зараз просто синтаксична зручність.

У Python немає хитрощів, щоб передати наміри асемблеру, оскільки він не використовує.


4
У Javascript є ++. Я не думаю, що це "хитрість донести наміри до асемблера". Крім того, у Python є байт-код. Тому я думаю, що причина в чомусь іншому.
Натан Девіс

13
Це "надання підказів компілятору" справді міф. Чесно кажучи, це німе доповнення до будь-якої мови, і воно порушує два наступні заповіді: 1. Ви не кодуєте комп'ютер для читання, кодуєте інший інженер для читання. І 2. Ви не кодуєте грамотного інженера, який повинен читати, ви кодуєте грамотного інженера, який має читати, поки знесилений о 3 годині ночі і скакав на кофеїн.

3
@ tgm1024 Для справедливості, кодуючи напівдуплексний телетайп 10–30 символів в секунду, ви кодуєте, щоб ви могли ввести його до наступного тижня.
msw

4
@ tgm1024 Unix і C бачили основну частину свого початкового розвитку на PDP-11, які використовували неймовірно повільні телетипи для спілкування з користувачем. Хоча ви мертві прямо, що сьогодні кодування для машини здебільшого нерозумно, тоді ще вузьким місцем був інтерфейс людина / машина. Важко уявити, що ти працюєш повільно, якщо ніколи тобі не довелося.
msw

65

Я завжди вважав, що це стосується цієї лінії дзен пітона:

Має бути один - і бажано лише один - очевидний спосіб зробити це.

x ++ і x + = 1 роблять точно те саме, тому немає обох причин.


10
one--дорівнює нулю?
Андре Хольцнер

25
one--- це одне у реченні, але відразу після цього нуль. Таким чином, цей «коан» також натякає на те, що оператори збільшення / зменшення не очевидні.
Віктор К

14
@EralpB Якщо ви видалите + =, ви не можете робити такі речі, як x + = 10. + = є більш загальним випадком ++
Rory

8
Також: "Явне краще, ніж неявне".
Бер

2
Однозначно не те саме, тому що x + = 1 НЕ є виразом - це твердження - і воно ні до чого не оцінює. Ви не можете робити такі речі, як: 'row [col ++] = a; рядок [col ++] = b '. Не кажучи вже про пред-інк і пост-інчі, які мають c ++.
Урі

38

Звичайно, ми могли б сказати, що «Гвідо просто вирішив так», але я думаю, що питання справді стосується причин такого рішення. Я думаю, що є кілька причин:

  • Він поєднує в собі заяви і вирази, що не є хорошою практикою. Дивіться http://norvig.com/python-iaq.html
  • Зазвичай заохочує людей писати менш читабельний код
  • Як уже згадувалося, додаткова складність у мовній реалізації, яка непотрібна в Python

12
Радий, що нарешті хтось згадав про аспект твердження та вираження У призначенні C - це вираз, і це оператор ++. У присвоєнні Python є оператором, тому, якщо він мав ++, він, ймовірно, повинен був бути також твердженням про призначення, (і навіть менш корисним або необхідним).
мартіно

Домовились - якщо б це були заяви, то як мінімум було б абсолютно безглуздо говорити про різницю між пост- та дооператорами.
Кроуман

17

Тому що в Python цілі числа незмінні (int's + = насправді повертає інший об'єкт).

Крім того, з ++ / - вам потрібно потурбуватися про попереднє збільшення / зменшення, і для цього потрібно лише ще один натискання клавіші x+=1. Іншими словами, це дозволяє уникнути потенційної плутанини за рахунок дуже невеликого прибутку.


ints незмінні і в C. Якщо ви так не вважаєте, спробуйте змусити ваш компілятор C створити код для 42++... Щось подібне (зміна буквальної константи) насправді було можливим у деяких старих компіляторах Fortran (або я так читав): усі майбутні використання цього буквального в програмі виконання дійсно матиме інше значення. Щасливого налагодження!
Lutz Prechelt

10
Правильно. 42 - буквальна константа . Константи (або, принаймні, повинні бути) незмінні. Це не означає, що C ints взагалі незмінні. А intв С просто позначає місце в пам'яті. І біти в цьому місці дуже сильно змінюються. Наприклад, ви можете створити посилання на intта змінити референта цієї посилання. Ця зміна помітна у всіх посиланнях (включаючи оригінальну intзмінну) на це місце. Це ж не стосується цілого об'єкта Python.
Натан Девіс

x + = 1 не стає пам'яттю. Python виконує виклик функції, щоб додати 1 до змінної; це жалко.
PalaDolphin

12

Чіткість!

Python багато в чому стосується ясності, і жоден програміст, ймовірно, не може правильно відгадати значення, --aякщо тільки він не вивчить мову, що має цю конструкцію.

Python також багато про уникнення конструкцій, які++ викликають помилки, і оператори, як відомо, є багатими джерелами дефектів. Цих двох причин достатньо, щоб не було цих операторів в Python.

Рішення про те, що Python використовує відступ для позначення блоків, а не синтаксичних засобів, таких як певна форма дужки початку / кінця або обов'язкове маркування кінця, в основному базується на тих же міркуваннях.

Для ілюстрації погляньте на дискусію навколо впровадження умовного оператора (на C cond ? resultif : resultelse:) в Python у 2005 році. Прочитайте принаймні перше повідомлення та повідомлення про рішення цієї дискусії. (у яких раніше було кілька попередників на ту саму тему).

Дрібниці: ПЕП, про який часто згадується, - це "Пропозиція щодо розширення Python" PEP 308 . LC означає розуміння списку , GE означає генераторне вираження (і не хвилюйтесь, якщо вони вас бентежать, вони не є одним з небагатьох складних місць Python).


10

Моє розуміння того, чому 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 новий об'єкт, а приріст стартера. Все це є IMHO для мінімізації плутанини. Для кращого розуміння дивіться, як працюють змінні python:

Чому в Python чому функція може змінювати деякі аргументи так, як сприймається абонентом, а не інші?

Чи Python викликає значення за дзвінками чи за посиланням? Ні.

Чи проходить Python за значенням чи посиланням?

Чи Python проходить через посилання чи пропускає значення?

Python: Як мені передавати змінну за посиланням?

Розуміння змінних Python та управління пам'яттю

Емуляція поведінки прохідних значень у python

Функції Python викликають за посиланням

Код, як Pythonista: Idiomatic Python


9

Це було просто спроектовано саме так. Оператори збільшення та скорочення - це лише ярлики x = x + 1. Python, як правило, прийняв проектну стратегію, яка зменшує кількість альтернативних способів виконання операції. Доповнене призначення є найбільш близьким до операторів збільшення / зменшення в Python, і вони навіть не були додані до Python 2.0.


3
Так друже, як ви могли б замінити return a[i++]з return a[i=i+1].
Luís de Sousa

7

Я дуже новачок у python, але підозрюю, що причина полягає в тому, що в мові робиться наголос між змінними та незмінними об'єктами. Тепер я знаю, що x ++ можна легко інтерпретувати як x = x + 1, але це ДУЖЕ, як ви нарощуєте на місці об'єкт, який може бути незмінним.

Просто моя здогадка / почуття / примха.


У цьому аспекті x++вони ближче, x += 1ніж до x = x + 1цих двох, які також змінюють свою роль і на об'єктах, що змінюються.
glglgl

4

По-перше, на Питона впливає лише побічно С; на нього сильно впливає ABC , який, очевидно, не має цих операторів , тому не повинно бути великим сюрпризом, щоб не знайти їх і в Python.

По-друге, як говорили інші, збільшення та зменшення підтримуються +=і -=вже є.

По-третє, повна підтримка ++та-- набору операторів операторів зазвичай включає підтримку як версій префікса, так і їх постфікса. У C і C ++ це може призвести до того, що всі види "чудових" конструкцій, які, здається мені, суперечать духу простоти та прямолінійності, які підтримує Пітон.

Наприклад, хоча while(*t++ = *s++);досвідчений програміст може здаватися простим і елегантним, але хтось його вивчає, він є не що інше, а просто. Вкиньте суміш прирістків і зменшень префікса та постфікса, і навіть багатьом профі доведеться зупинитися і трохи подумати.


3

Я вважаю, що це випливає з віри Python, що "явне краще, ніж неявне".


Ну, ви не пишите явно "почати" і "закінчити" заяви в Python, правда? Хоча я згоден із твердженням, я думаю, що в цьому є межі. Хоча ми можемо сперечатися про ці межі, я думаю, що ми всі можемо погодитися, що існує лінія, яку недоцільно перетнути. А оскільки існує стільки думок та обґрунтування цього рішення, я не думаю, що це був чіткий вибір. Принаймні, я не можу знайти джерело, де прямо сказано
Хасан Амморі

3

Це може бути тому, що @GlennMaynard розглядає питання як порівняно з іншими мовами, але в Python ви все робите так, як пітон. Це не питання "чому". Це там, і ви можете робити речі з таким же ефектом x+=. У "Дзен Пітона" зазначено: "Вирішити проблему має бути лише один спосіб". Багаторазовий вибір великий у мистецтві (свобода вираження поглядів), але невдалий у техніці.


2

++Клас операторів вираз з побічними ефектами. Це звичайно не зустрічається в Python.

З цієї ж причини призначення не є виразом у Python, тим самим запобігаючи загальній if (a = f(...)) { /* using a here */ }ідіомі.

Нарешті, я підозрюю, що там оператор не дуже відповідає опорній семантиці пітонів. Пам'ятайте, що Python не має змінних (або покажчиків) із семантикою, відомою з C / C ++.


1
ніщо не заважає викликати функцію з побічним ефектом при розумінні тесту / вираження / списку: f(a)де aсписок, якийсь незмінний об'єкт.
Жан-Франсуа Фабре

1

Можливо, кращим буде питання, чому ці оператори існують в операторах C. K&R називає операторів збільшення та зменшення „незвичними” (Розділ 2.8стор. 46). Вступ називає їх «більш короткими та часто більш ефективними». Я підозрюю, що той факт, що ці операції завжди піддаються маніпуляції з покажчиком, також зіграв важливу роль у їх впровадженні. У Python, ймовірно, було вирішено, що не має сенсу намагатися оптимізувати прирости (адже я тільки що робив тест на C, і здається, що створена gcc збірка використовує addl замість incl в обох випадках), і немає арифметика вказівника; тож це був би ще один спосіб зробити це, і ми знаємо, що Python це ненавидить.


1

як я зрозумів це, щоб ви не думали, що значення в пам'яті змінюється. в c, коли ви робите x ++, значення x в пам'яті змінюється. але в python усі числа незмінні, отже, адреса, на яку вказував x, як і раніше, має x не x + 1. коли ви пишете x ++, ви б подумали, що x змінить те, що відбувається насправді, - це те, що рефлексія x змінюється на місце в пам’яті, де зберігається x + 1, або відтворювати це місце, якщо doe не існує.


1
То що ж робить це ++і чим відрізняється від += 1?
Бер

1

Щоб заповнити вже хороші відповіді на цій сторінці:

Припустимо, ми вирішимо зробити це префіксом ( ++i), який би порушив оператори unary + та -.

Сьогодні префіксація за допомогою ++або --нічого не робить, тому що вона дає можливість унарному оператору плюс двічі (нічого не робить) або унарному мінусу двічі (двічі: скасовує себе)

>>> i=12
>>> ++i
12
>>> --i
12

Тож це потенційно може порушити цю логіку.


1

В інших відповідях описано, чому він не потрібен ітераторам, але іноді це корисно, призначаючи збільшити змінну в рядку, ви можете досягти того ж ефекту, використовуючи кортежі та багаторазове призначення:

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
: = присвоєння - це ганьба
nehem

0

Я думаю, що це стосується понять незмінності та незмінності предметів. 2,3,4,5 незмінні в пітоні. Дивіться зображення нижче. 2 має фіксований ідентифікатор до цього процесу python.

Ідентифікатор констант і змінних

x ++ по суті означатиме приріст на місці, як C. У C x ++ виконує кроки на місці. Отже, x = 3, а x ++ збільшить 3 у пам'яті до 4, на відміну від python, де 3 все ще існуватиме в пам'яті.

Таким чином, у python вам не потрібно відтворювати значення в пам'яті. Це може призвести до оптимізації продуктивності.

Це відповідь, заснована на переконанні.


0

Я знаю, що це стара нитка, але найпоширеніший випадок використання для ++ 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()) :
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.