Vamos, por exemplo, supor que eu quero subclassear dict
e ter todas as chaves em maiúsculas:
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())
Isso funciona até certo ponto,
>>> ex = capdict(map(reversed,enumerate("abc")))
>>> ex
{'A': 0, 'B': 1, 'C': 2}
>>> ex['a']
0
mas, é claro, apenas para métodos que lembrei de implementar, por exemplo
>>> 'a' in ex
False
não é o comportamento desejado.
Agora, a maneira preguiçosa de preencher todos os métodos que podem ser derivados dos "essenciais" estaria se misturando collections.abc.MutableMapping
. Só que não funciona aqui. Presumo que os métodos em questão ( __contains__
no exemplo) já sejam fornecidos por dict
.
Existe uma maneira de comer meu bolo e comê-lo? Alguma mágica para deixar MutableMapping
apenas ver os métodos que eu substituí para que ele reimplemente os outros com base nesses?
python
python-3.x
Paul Panzer
fonte
fonte
MutableMapping
. Consulte Dicionário que não diferencia maiúsculas de minúsculas .os._Environ
.Respostas:
O que você poderia fazer:
Isso provavelmente não funcionará bem (ou seja, não é o design mais limpo), mas você pode herdar do MutableMapping primeiro e depois do ditado segundo.
O MutableMapping usaria os métodos que você implementou (porque são os primeiros na cadeia de pesquisa):
Melhor maneira:
A abordagem mais limpa (fácil de entender e testar) é apenas herdar do MutableMapping e implementar os métodos necessários usando um ditado regular como armazenamento de dados base (com composição e não herança):
fonte
super
s pordict
s explícitos , ele parece funcionar, excetolen
retornos0
. De onde isso está vindo?(D, MutableMapping, dict)
. Esse é o método MutableMappiing .__ len __ () que sempre retorna 0. Não era para ser chamado diretamente - ele sempre deve ser substituído. É por isso que você precisa ligardict.__len__(self)
diretamente. E essa é uma das razões pelas quais eu disse "isso provavelmente não vai funcionar bem" ;-)