2016-07-13 70 views
5

Avevo bisogno di creare una classe che dicesse esteso e si imbattesse in un problema interessante illustrato dall'esempio stupido nell'immagine qui sotto.sottoclasse dict; dict.update restituisce il valore dell'incorretto - python bug?

subclassing_dict_problem

Perché d.update() ignorando della classe __getitem__?

EDIT: Questo è in python2.7 che non sembra contenere collezioni.UserDict Thinking UserDict.UserDict è l'equivalente Ho provato questo, e si avvicina, ma si comporta ancora in modo interessante.

updated to use UserDict

+0

Possibile duplicato di [Python: come "perfettamente" sovrascrive un dettato] (http: // stackoverflow.it/questions/3387691/python-how-to-perfect-override-a-dict) – styvane

+0

La mia domanda non è come aggirare questo, ma 'perché' sta succedendo. Ho finito con la sottoclassi di MutableMapping per completare il mio lavoro, ma questo sembra un comportamento strano e non documentato. – Kirk

+0

[Sottoclassi di tipi predefiniti] (https://pypy.readthedocs.io/en/latest/cpython_differences.html#subclasses-of-built-in-types) – styvane

risposta

6

Questo è un esempio del open-closed-principle (la classe è aperta per estensione ma chiuso per la modifica). È positivo perché consente ai sottoclassi di estendere o sovrascrivere un metodo senza attivare involontariamente modifiche del comportamento in altri e senza rompere gli invarianti delle classi.

Facciamo anche questo in puro codice Python; ad esempio, inside the pure python ordered dict code, la chiamata locale della classe da __init__() a update() viene eseguita utilizzando name mangling. Ciò consente a un subclasser di ignorare update()without accidentally breaking__init__().

A volte questo è un inconveniente. Ciò significa che un subclasser deve ignorare tutti i metodi di cui si desidera modificare il comportamento, tra cui get(), update() e altri. Tuttavia, vi sono vantaggi compensativi (protezione degli invarianti interni, prevenzione dei dettagli di implementazione dall'uscita dall'astrazione e possibilità per gli utenti di assumere che i metodi siano indipendenti l'uno dall'altro).

Questo stile (scelto da Guido sin dall'inizio) è l'impostazione predefinita per i tipi predefiniti (altrimenti dovremmo sempre combattere le violazioni invarianti di segfault) e per alcune classi di python pure.

Facciamo documenti quando c'è una partenza dal valore predefinito. Ad esempio, lo cmd module utilizza framework design pattern, consentendo all'utente di definire vari metodi do_action(). Inoltre, alcuni dei moduli http fanno lo stesso, in particolare documentando che viene chiamato il numero do_GET() method di un utente e questo è il modo in cui si collegano gestori di eventi HTTP personalizzati.

In assenza di ganci metodo specificamente documentate (cioè quelli sopra elencati o metodi simili dict.__missing__(), un subclasser deve presumere metodo indipendenza. Altrimenti, come sei tu per sapere se __getitem__() chiamate get() sotto il cofano o viceversa?

FWIW, questo non è unico per Python. si ha un po 'in programmazione orientata agli oggetti. metodi classi correttamente progettati due documenti principali che influenzano il comportamento di altri metodi o si presume essere indipendenti.

ci potrebbe essere necessario essere una FAQ per questo, ma nulla è rotto o sbagliato qui (diverso da Python h avanza troppe varianti dict tra cui scegliere). Se qualcuno assume erroneamente o ritiene che __getitem__() debba essere chiamato dagli altri metodi di accesso, scoprirà molto rapidamente che l'assunto è sbagliato (ovvero se eseguono anche test minimi sul codice).