Pattern di delega in Python: è impopolare? Non è considerato Pythonic?

-2

Come persona di Ruby / Rails, mi occupo spesso della delega dei metodi. È spesso conveniente delegare un metodo a un oggetto composto oa una costante. Ruby ha anche un metodo helper def_delegator per creare facilmente i delegator e l'ActiveSupport di Rails migliora l'interfaccia del builtin con delegate .

Tuttavia, quando ho guardato Python, non ho trovato nessun aiuto per creare delega, né in stdlib né su PyPi. Il meglio che posso trovare è qualche raccomandazione su StackOverflow per sovrascrivere manualmente __getitem__ per dichiarare i delegatori.

Quindi devo chiedere: questo modello è considerato non-Pythonic? O mi sto perdendo qualcosa?

Grazie.

    
posta art-solopov 07.11.2018 - 22:27
fonte

1 risposta

3

Sebbene la delega sia possibile, in effetti non è comune.

  1. In molti casi in cui potresti raggiungere la delega, potresti anche utilizzare l'ereditarietà multipla. Ruby non ha ereditarietà multipla, quindi deve utilizzare altri approcci come mixin o delega. Python ha qui una semantica più flessibile.

  2. La delega basata su __getattr__ e / o __getattribute__ è complessa e richiede una buona comprensione dei dettagli di basso livello di Python da implementare correttamente. Questo interagisce con il protocollo descrittore e le caratteristiche di introspezione come dir() o help() e con altri metodi dunder come __str__ o __add__ : non è possibile delegare implicitamente metodi dunder, ma dovrebbe implementare un metodo che esegue la delega.

  3. Questa complessità è percepita come non-Pythonic. "Explicit è meglio di implicito."

  4. Invece della delega tramite __getattr__ , puoi semplicemente implementare manualmente i metodi o le proprietà che desideri delegare. Puoi utilizzare metaprogrammazione (tramite metaclassi o decoratori di classi) per semplificare questa operazione oppure utilizzare il protocollo descrittore per creare membri della classe che eseguono la delega quando vi si accede tramite un'istanza.

  5. La delega è lenta, specialmente se basata su funzioni di riflessione o metaprogrammazione.

I descrittori sono oggetti che implementano un membro della classe. Vengono richiamati in modi diversi a seconda che si acceda a un membro di classe o istanza. Le funzioni e le proprietà sono implementazioni di descrittori comunemente utilizzate, ma è possibile creare descrittori definiti dall'utente. Tutto ciò che ha un metodo __get__ può essere usato come descrittore. In un progetto ho implementato un descrittore per eseguire la delega, ad es. usato come:

class Foo:
  delegated_method = delegate('TargetType', 'delegated_method', to='_target')

  def __init__(self, target):
    self._target = target

# Foo().delegated_method => Foo()._target.delegated_method
# Foo.delegated_method => returns the descriptor
# help(Foo.delegated_method)  # works

Alla fine, la complessità e l'impatto sulle prestazioni dell'uso dei descrittori era troppo importante in quel progetto, e ho semplicemente spiegato esplicitamente la delega.

    
risposta data 07.11.2018 - 23:51
fonte

Leggi altre domande sui tag