Quali sono i potenziali pericoli dell'utilizzo di questo tipo di trucco cheat in Python?

1

In un programma su cui sto lavorando, ho bisogno di fare una notevole quantità di riflessioni in tempo reale al fine di mantenere un elenco di "attributi" conosciuti in tutta la struttura del programma (da utilizzare con una sorta di "assistente di programmazione virtuale" "). Mi è venuto in mente un modo "cheaty" per farlo (di cui sono francamente orgoglioso), che è essenzialmente simile al seguente:

old_getattribute = obj.__getattribute__
def new_getattribute(self, attr):
    # various things...
    return old_getattribute(attr)
methods = {"__getattribute__" : new_getattribute}
obj.__class__ = type(              # Dynamically create a new class
    "%s" % obj.__class__.__name__, # whose name is _CLASS
    (obj.__class__, ),             # which subclasses CLASS
    methods)                       # and uses the new __getattribute__

In sostanza, creo dinamicamente un nuovo tipo che sottoclasse il tipo originale, utilizzando un nuovo metodo __getattribute__ , quindi riassegna l'% interno% co_de dell'oggetto a questo nuovo tipo dinamico.

Per quanto io sia stupito e felice che funzioni (almeno in Python > = 3.6), sono ancora sul punto di usarlo. Nella mia passata programmazione in Python, qualsiasi tipo di modifica dei metodi magici di un oggetto da outside la definizione __class__ dell'oggetto era praticamente proibita, eppure qui sto facendo due volte in modi davvero incasinati.

Vorrei come usarlo, in quanto mi avrebbe risparmiato un sacco di tempo invece di tenere traccia dei singoli oggetti in un modo "appropriato" e quindi controllarli continuamente per le modifiche, ma io voglio per essere sicuro di non creare alcun potenziale pericolo per il resto del programma.

Quindi è quello che sono qui per chiedere. Da un punto di vista dell'architettura del software, quanto potenzialmente pericoloso è questo metodo e quali sono le insidie che potrei incontrare nel farlo funzionare? Sono sicuro che ci sono più di qualche OOP / principi di programmazione generale che sto violando gravemente con questo, ma sono disposto a lasciare che diapositiva se questo può essere "gestito".

    
posta user3002473 28.11.2018 - 19:46
fonte

1 risposta

4

Quando utilizzi __getattribute__ sei nel profondo del budello del modello a oggetti di Python. Le cose potrebbero funzionare, ma richiedono una solida comprensione. Inoltre, alcuni aspetti potrebbero essere i dettagli di implementazione di CPython e potrebbero non riuscire su altre implementazioni.

Cose da considerare:

  • __getattribute__ non è sufficiente per osservare le modifiche agli oggetti.
  • __getattribute__ non verrà chiamato quando si accede a metodi speciali e probabilmente non quando si accede all'oggetto dall'interno dell'interprete Python.
  • considera come questo interagisce con l'accesso dei membri della classe.
  • __class__ potrebbe non essere assegnabile.
  • Modifica delle interruzioni di classe type(x) is Foo controlli di stile.
  • I metaclassi potrebbero impedirti di estendere la classe originale.
  • La specifica di __getattribute__ implica un notevole overhead delle prestazioni. Questo potrebbe essere un po 'meglio se lo si implementa in C (a condizione che si stia usando CPython).

Da una prospettiva OOP, non stai più lavorando nel paradigma OO: invece di inviare messaggi ad altri oggetti, stai intercettando l'implementazione della spedizione dei messaggi della lingua. Questo è discutibile, e ha persino un nome: programmazione orientata agli aspetti. Python è abbastanza flessibile da escluderlo implicitamente, come hai mostrato. Tuttavia, potrebbe essere molto desiderabile non strumentare oggetti esistenti come questo, ma offrire un'API che renda più semplice la visualizzazione degli oggetti. Tale API potrebbe forse implementare proprietà che possono attivare una richiamata all'accesso.

Se è necessario osservare oggetti non durante la loro normale esecuzione ma per alcune analisi, potrebbe essere più semplice applicare una patch al runtime di CPython con un hook aggiuntivo. Potresti trovare qualche sovrapposizione con gli hook di debugger esistenti.

    
risposta data 29.11.2018 - 16:43
fonte

Leggi altre domande sui tag