Такі «розширені» оператори присвоєння, як, наприклад, +=були представлені в 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])після виконання рядка, який викликає помилку.