Va bene accedere ai membri privati mentre si fa il confronto della stessa classe?

1

Sto scrivendo una classe che fondamentalmente è un wrapper attorno ad un dizionario con alcune funzionalità extra. Questo dizionario è memorizzato come membro protetto _store . Ora sto scrivendo un metodo __eq__ per confrontare oggetti della mia classe. Il criterio è, se i dizionari sottostanti sono uguali, gli oggetti sono uguali, quindi l'approccio più semplice sarebbe:

def __eq__(self, other):
    return self._store == other._store

Ma questo comporta l'accesso ai membri protetti di un terzo oggetto. Sebbene questo terzo oggetto appartenga alla stessa classe di self . Possiamo considerare questo incapsulamento di rottura ??

L'altra opzione consiste nel fare un confronto tra i due oggetti, che porta a un codice un po 'meno efficiente e più lungo (confronto tra le chiavi e verifica che le coppie chiave-valore di un oggetto siano uguali a quelle dell'altro oggetto) .

    
posta bgusach 13.12.2014 - 11:14
fonte

2 risposte

7

Dal momento che l'hai taggato con , ti darò il Prospettiva Python su questo.

In Python, questo è completamente normale . Gli attributi non sono privati, sono semplicemente contrassegnati come 'interni', per convenzione, usando un trattino basso di primo piano. Quindi _store è qualcosa che è 'interno' alla classe, proprio come l'implementazione di __eq__ è una questione interna.

Non stai rompendo l'incapsulamento qui; stai semplicemente fornendo una corretta implementazione di un metodo di aggancio. L'accesso a other._store qui non è diverso dall'accesso a self._store in questo senso. Questo perché Python è un linguaggio pragmatico, non è un linguaggio OO purista (puoi usare paradigmi funzionali e procedurali ogni volta che ritieni che si adatti meglio allo spazio del problema, per esempio).

Tieni presente che potresti voler restituire l'oggetto singleton NotImplemented per i confronti che la tua classe non supporta:

def __eq__(self, other):
    if not isinstance(other, MyClass):  # or not hasattr(other, '_store') perhaps
        return NotImplemented
    return self._store == other._store

Python delegherebbe quindi il test all'oggetto other ; se non implementa il metodo __eq__ o restituisce NotImplemented , allora Python torna a un test di identità ( self is other ).

Troverai questo modello (usando gli attributi interni nei metodi di confronto) in tutta la libreria standard di Python. Ad esempio, tutti i metodi di confronto per la decimal.Decimal() classe delegati al Decimal._cmp() metodo , e l'implementazione per tale metodo si basa quasi esclusivamente sull'utilizzo di attributi interni e metodi ( _is_special , _isinfinity() , _sign , _exp e _int ), accessibili sia su self sia su other .

Altri esempi:

risposta data 13.12.2014 - 14:06
fonte
1

L'hai taggato con , quindi la risposta è no. Il fatto che gli oggetti solo siano a conoscenza della loro implementazione / rappresentazione privata propria e non di quella di altri oggetti anche dello stesso tipo è definizione della caratteristica dell'astrazione dei dati orientata agli oggetti rispetto ai tipi di dati astratti, dove le istanze di un do ADT sono a conoscenza dell'implementazione privata di altre istanze dello stesso tipo.

Se hai familiarità con Java, allora c'è un modo semplice per pensarci: class == ADT, interface == oggetto.

Questo è magnificamente spiegato in Informazioni sull'astrazione dei dati, rivisitato di William R. Cook.

Si noti che non c'è nulla di sbagliato negli ADT di per sé, ma a) come suggerisce il nome, si basano sui tipi (nel senso teorico-tipo della parola, con il quale significano tipi statici ), quale Python non ha, e b) hai taggato la domanda in modo specifico con .

Si noti inoltre che non è abbastanza facile definire cosa significhi "due istanze ADT dello stesso tipo" in Python, poiché, dopo tutto, le classi non sono tipi, anatre sono.

    
risposta data 13.12.2014 - 13:12
fonte

Leggi altre domande sui tag