Давайте для примера предположим, что я хочу создать подкласс dict
и сделать все ключи заглавными:
class capdict(dict):
def __init__(self,*args,**kwds):
super().__init__(*args,**kwds)
mod = [(k.capitalize(),v) for k,v in super().items()]
super().clear()
super().update(mod)
def __getitem__(self,key):
return super().__getitem__(key.capitalize())
def __setitem__(self,key,value):
super().__setitem__(key.capitalize(),value)
def __delitem__(self,key):
super().__detitem__(key.capitalize())
Это работает до такой степени,
>>> ex = capdict(map(reversed,enumerate("abc")))
>>> ex
{'A': 0, 'B': 1, 'C': 2}
>>> ex['a']
0
но, конечно, только для методов, которые я запомнил, например, для реализации
>>> 'a' in ex
False
не желаемое поведение.
Теперь ленивый способ заполнения всех методов, которые могут быть получены из «основных», будет смешиваться collections.abc.MutableMapping
. Только здесь это не работает. Я предполагаю, потому что рассматриваемые методы ( __contains__
в примере) уже предоставлены dict
.
Есть ли способ получить мой пирог и съесть его? Какая-то магия, позволяющая MutableMapping
видеть только те методы, которые я переопределил, чтобы переопределить другие, основанные на них?
python
python-3.x
Пол Панцер
источник
источник
MutableMapping
. Смотрите словарь без учета регистра .os._Environ
.Ответы:
Что вы могли бы сделать:
Это, вероятно, не сработает хорошо (т.е. не самый чистый дизайн), но вы могли бы наследовать сначала от MutableMapping, а затем от dict во- вторых.
Тогда MutableMapping будет использовать любые методы, которые вы реализовали (потому что они являются первыми в цепочке поиска):
Лучший путь:
Самый чистый подход (простой для понимания и тестирования) состоит в том, чтобы просто наследовать от MutableMapping, а затем реализовать необходимые методы, используя обычный dict в качестве основного хранилища данных (с композицией, а не наследованием):
источник
super
s на явныеdict
s, тогда это, кажется, работает, кромеlen
возвратов0
. Откуда это?(D, MutableMapping, dict)
. Это метод MutableMappiing .__ len __ (), который всегда возвращает 0. Он не был предназначен для прямого вызова - он всегда должен быть переопределен. Вот почему вы должны позвонитьdict.__len__(self)
напрямую. И это одна из причин, по которой я сказал: «Скорее всего, это не сработает» ;-)