Такі «розширені» оператори присвоєння, як, наприклад, +=
були представлені в Python 2.0, який був випущений у жовтні 2000 р. Дизайн та обгрунтування описані в PEP 203 . Однією з заявлених цілей цих операторів була підтримка операцій на місці. Написання
a = [1, 2, 3]
a += [4, 5, 6]
повинен оновити список a
на місці . Це має значення, якщо до списку є інші посилання a
, наприклад, коли він a
був отриманий як аргумент функції.
Однак операція не завжди може відбуватися на місці, оскільки багато типів Python, включаючи цілі числа та рядки, незмінні , тому, наприклад, i += 1
для цілого числа, i
можливо, це не може працювати на місці.
Підсумовуючи це, оператори розширеного призначення повинні були працювати на місці, коли це було можливо, і створювати новий об'єкт в іншому випадку. Для полегшення цих цілей дизайну, вираз x += y
було визначено таким чином, щоб він поводився таким чином:
- Якщо
x.__iadd__
визначено, x.__iadd__(y)
оцінюється.
- В іншому випадку, якщо
x.__add__
це буде реалізовано x.__add__(y)
, оцінюється.
- В іншому випадку, якщо
y.__radd__
це буде реалізовано y.__radd__(x)
, оцінюється.
- Інакше виникне помилка.
Перший результат, отриманий цим процесом, буде присвоєно назад x
(якщо цей результат не є NotImplemented
одинарним, і в цьому випадку пошук продовжується з наступним кроком).
Цей процес дозволяє реалізувати типи, які підтримують місцеві зміни __iadd__()
. Типи, які не підтримують модифікацію на місці, не потребують додавання нових магічних методів, оскільки Python автоматично відновлюється x = x + y
.
Отже, давайте нарешті підійдемо до вашого актуального питання - чому ви можете додати кортеж до списку за допомогою оператора розширеного призначення. З пам’яті історія цього була приблизно така: list.__iadd__()
Метод був реалізований для простого виклику вже існуючого list.extend()
методу в Python 2.0. Коли ітератори були введені в Python 2.1, list.extend()
метод було оновлено, щоб прийняти довільні ітератори. Кінцевим результатом цих змін стало те, що він my_list += my_tuple
працював, починаючи з Python 2.1. Однак list.__add__()
метод ніколи не повинен був підтримувати довільних ітераторів як правий аргумент - це вважалося недоцільним для сильно набраної мови.
Я особисто думаю, що реалізація розширених операторів в Python виявилася занадто складною. Він має багато дивних побічних ефектів, наприклад, цей код:
t = ([42], [43])
t[0] += [44]
Другий рядок піднімається TypeError: 'tuple' object does not support item assignment
, але операція все одно успішно виконується - t
буде ([42, 44], [43])
після виконання рядка, який викликає помилку.