L'argomento dell'ereditarietà di zope.interface (fornito da vs isinstance)

4

Quali limitazioni eredita l'ereditarietà di un'interfaccia attraverso una classe base astratta presente che è indirizzata da zope.interface?

Nella successiva discussione tenuta nel 2010 da Jeff Rush parla delle interfacce, alle 11:50 Jeff sostiene che con la condizione che tu sia libero dalla gerarchia dell'eredità. Perché questo è importante?

Se volessi utilizzare un'interfaccia e ereditare il comportamento da un'altra classe base, Python mi concede l'opportunità di farlo con eredità multipla. Capisco che l'eredità multipla dovrebbe essere evitata, e un design compositivo da considerare come un'alternativa, ma in questo caso non sto ereditando il comportamento dall'abc ma piuttosto solo un'interfaccia, quindi non sono realmente ereditario multiplo nel comportamento senso.

Non capisco l'argomento dell'eredità ..

Grazie in anticipo per condividere la tua visione.

    
posta Dowwie 15.06.2014 - 13:12
fonte

1 risposta

4

Il video non sembra essere disponibile a partire da dicembre 2016, ma sono d'accordo con te sul fatto che l'ereditarietà dell'interfaccia non è problematica come l'ereditarietà dell'implementazione. Vedi link per esempio.

Tuttavia, un senso in cui la relazione "fornitore" di zope.interface ci libera dalla gerarchia dell'ereditarietà è che consente agli oggetti di fornire un'interfaccia anche se la loro classe non lo fa. Il link mostra esempi di oggetti che forniscono direttamente un'interfaccia sebbene le loro rispettive classi non lo facciano.

Ad esempio, se un'interfaccia IWriter richiede i metodi write e flush , allora un modulo che definisce le funzioni write e flush (e chiama zope.interface.moduleProvides(IWriter) ) fornisce quell'interfaccia, anche anche se i moduli in generale non lo fanno.

Questo è anche il motivo per cui i metodi di interfaccia Zope non nominano self come parametro - self è un dettaglio di implementazione particolare per i metodi di istanza di classe.

Questa capacità per i singoli oggetti di fornire un'interfaccia diventa particolarmente utile con oggetti che racchiudono un altro oggetto e mappano dinamicamente i suoi metodi.

Ad esempio, supponiamo di avere:

class IWriter(zope.interface.Interface):
    def write(s):
        """Write stuff"""
    def flush():
        """Flush stuff"""

class TextWriter:
    zope.interface.implements(IWriter)
    def write(self, s):
        ...
    def flush(self):
        ...

tw = TextWriter()

do_something(tw)

Se visualizziamo un problema in cui l'output tw non viene scaricato a volte, possiamo utilizzare lo strumento per i metodi TextWriter per visualizzare le informazioni di debug (ad esempio log(timestamp, caller, methodname) ). Tuttavia, il codice per generare le informazioni timestamp e caller è complesso e deve essere aggiunto in più punti. E ora ogni istanza di TextWriter mostrerà le informazioni di debug.

Invece, potremmo racchiudere il particolare TextWriter di interesse in un oggetto wrapper che registra le sue chiamate di metodo.

class DebugWrapper:

    def __init__(self, wrapped):
        self._wrapped = wrapped

    def __getattr__(self, name):
        ... # generate timestamp and caller
        log(timestamp, caller, name)
        return getattr(self._wrapped, name)

dtw = DebugWrapper(tw)

do_something(dtw)

Tieni presente che DebugWrapper è generico. Può avvolgere qualsiasi oggetto. Potrebbe essere importato da una libreria separata. È indipendente dall'interfaccia IWriter , e ciò è positivo poiché possiamo riutilizzarlo più facilmente altrove.

Ma se la funzione do_something si aspetta di ricevere un fornitore dell'interfaccia IWriter ora abbiamo il problema che dtw soddisfa la sintassi dell'interfaccia ma non fornisce "ufficialmente" l'interfaccia.

Questa è una distinzione importante.

Le interfacce non definiscono solo una firma sintattica. Definiscono anche il significato semantico della sintassi. Con le interfacce possiamo specificare se due oggetti che forniscono gli stessi metodi forniscono effettivamente la stessa semantica. Questa è una grande differenza per l'uso comune di Python della digitazione anatra, dove la stessa sintassi implica la stessa semantica.

Ad ogni modo, la soluzione al nostro problema è informare tutti che l'oggetto dtw fornisce effettivamente l'interfaccia IWriter , anche se la sua classe DebugWrapper non lo fa.

zope.interface.directlyProvides(dtw, IWriter)
    
risposta data 14.12.2016 - 08:41
fonte

Leggi altre domande sui tag