4

Существует метод магии Python __setitem__ для назначения = типам последовательностей. Существуют ли магические методы для расширенного задания += на уровне контейнера? Операция, похоже, изящно разбивается на расширенное назначение типа элемента. Это логично. Но для всего остального есть волшебный метод, я думал, что для этих операторов должен быть набор методов для типа последовательности. Я пропустил это?Магический метод для `self [key] + = value`?

Приложение представляет собой своего рода базу данных. Подумайте об осуществлении __getitem__ с помощью SELECT и __setitem__ с INSERT. Должно быть что-то вроде __additem__ и т. Д. Для UPDATE, правильно?

from __future__ import print_function 
class Item(object): 
    def __init__(self, value): 
     self.value = value 
    def __str__(self): 
     return "Item " + str(self.value) 
    def __iadd__(self, other): 
     print("Item iadd", self, other) 
     return Item(self.value + "+" + other.value) 

class Container(object): 
    def __getitem__(self, key): 
     print("Container getitem", key) 
     return Item(key) 
    def __setitem__(self, key, value): 
     print("Container setitem", key, value) 
     return self 
    def __additem__(self, key, value): 
     print("Container additem would be nice", key, value) 
     return self 

Вот SELECT:

>>> c = Container() 
>>> _ = c['key'] 
Container getitem key 

Вот ВСТАВИТЬ:

>>> c['key'] = Item('other') 
Container setitem key Item other 

Как реализовать UPDATE? Без разбивки на SELECT, и INSERT:

>>> c['key'] += Item('other') 
Container getitem key 
Item iadd Item key Item other 
Container setitem key Item key+other 

Так есть способ реализации дополненного назначения иначе, чем шаги разбитых? Не помещая все поведение в класс Item?


Вы можете вырезать и вставить код выше в интерпретатор Python, или попробовать его на этом Python скрипкой: http://pythonfiddle.com/add-item-for-sequence/


related question показывает декомпиляция self[key] += value

ответ

3

Нет, есть нет магия __additem__ способ.

c[k] += v превращается в вызов магического метода: c.__setitem__(c.__getitem__(k).__iadd__(v)).

Звонок __setitem__ включен, потому что не все объекты Python поддерживают добавление на месте. Неизменяемые объекты (например, int и float), а не __add__ будут называться вместо __iadd____add__должно вернуть новое значение).

Я думаю, что единственный способ заставить вашу базу данных работать так, как вы хотите, - написать __getitem__ так, чтобы он возвращал специальный тип «прокси-объекта». Прокси-сервер ничего не сделал бы изначально (у него нет собственного поведения). Однако, когда на него был обнаружен атрибут или метод (или был вызван метод __magic__), он сделает необходимые операции с базой данных, чтобы заставить его работать. Для большинства методов и поиска атрибутов необходимо запросить базу данных для извлечения фактических данных, а затем вернуть соответствующий метод или значение. Если бы это было известно в месте способ модификации, который был вызван (как append или __iadd__, это может сделать другую операцию базы данных вместо того, чтобы (как UPDATE вместо SELECT).

Дать такой тип прокси не будет очень легко, но не абсурдно. Также будет много угловых случаев, если вы хотите обрабатывать многие типы объектов.В зависимости от того, насколько узким может быть множество типов, которыми может обладать ваша база данных, можно было бы сузить список методов и атрибутов, для которых вам нужен прокси, чтобы реплицировать только несколько (например, операторы арифметики и сравнения и, возможно, __int__ и __float__, если вы требуется только поддержка числовых типов).

С другой стороны, вы можете обнаружить, что это не стоит усилий по развитию, когда вы можете просто сделать SELECT и INSERT с меньшим количеством кода.