2015-11-11 13 views
6

Ho capito come sostituire i metodi in fase di esecuzione in Python passando attraverso questi collegamenti. [Link1, Link2, & Link3].Sostituzione del metodo in fase di runtime non aggiornando Attributi privati ​​

Quando ho sostituito un metodo "update_private_variable" di classe A, è stato sostituito ma non ha aggiornato la variabile privata.

import types 

class A: 
    def __init__(self): 
     self.__private_variable = None 
     self.public_variable = None 

    def update_private_variable(self): 
     self.__private_variable = "Updated in A" 

    def update_public_variable(self): 
     self.public_variable = "Updated in A" 

    def get_private_variable(self): 
     return self.__private_variable 

class B: 
    def __init__(self): 
     self.__private_variable = None 
     self.public_variable = None 

    def update_private_variable(self): 
     self.__private_variable = "Updated in B" 

    def update_public_variable(self): 
     self.public_variable = "Updated in B" 

Quando si chiama il metodo senza sostituzione:

a_instance = A() 
a_instance.update_private_variable() 
print(a_instance.get_private_variable()) 
#prints "Updated in A" 

Quando si chiama il metodo dopo la sostituzione:

a_instance = A() 
a_instance.update_private_variable = types.MethodType(B.update_private_variable, a_instance) 
a_instance.update_private_variable() 
print(a_instance.get_private_variable()) 
#prints None 

Mentre la sostituzione e chiamando un metodo che aggiorna variabile pubblica, funziona bene

a_instance = A() 
a_instance.update_public_variable = types.MethodType(B.update_public_variable, a_instance) 
a_instance.update_public_variable() 
print(a_instance.public_variable) 
#prints 'Updated in B' 

Esiste un altro modo per sostituire il metodo di un'istanza in fase di esecuzione, in modo che gli attributi privati ​​vengano aggiornati richiamando il metodo sostituito?

+0

ottengo un errore su 'a_instance.update_private_variable()' dopo aver rebinding 'update_private_variable'. 'TypeError: metodo non associato update_private_variable() deve essere chiamato con l'istanza B come primo argomento (ottenuto invece da un'istanza)' Inoltre non esiste un vero sistema pubblico/privato. 'public_variable' e' __private_variable' sono entrambi accessibili all'utente come gli altri. – SuperBiasedMan

+3

È probabile che si verifichino problemi con * "nome mangling" *, invocato dal nome dell'attributo '__leading_double_underscore' - utilizzare un' _leading_single_underscore' per indicare private-by-convention e riservare il doppio per evitare conflitti di nomi tra sottoclassi. – jonrsharpe

+0

@jonrsharpe: ho provato con '_leading_single_underscore', funziona correttamente. Ma come da mia esigenza, non posso cambiare la _ "convenzione di denominazione" _ – user3262851

risposta

1

L'idea alla base del nome manomissione consiste nel proteggere le variabili di classe base dall'essere incasinato dalle sottoclassi; in altre parole, non dovresti usarlo se pensi che le sottoclassi avranno una buona ragione per modificare quelle stesse variabili.

Detto questo, se si è già bene su questa strada e sono in grado (o non vogliono) per farla cambiare ora, è ancora possibile ottenere da, ma sarà brutto e fragili:

class B: 

    def update_private_variable(self): 
     self._A__private_variable = "Updated in B" 

Come si può vedere, si ha come prefisso la variabile nome-storpiato con una _ e il nome della classe della variabile è storpiato in alcune delle conseguenze:.

  • se si cambia il nome della classe, è necessario cambia il nome in tutti i riferimenti ad esso
  • non è possibile utilizzare facilmente lo stesso metodo update_private_variable (poiché è necessario indicare in qualche modo la classe di destinazione ... suppongo che si possa passare alla classe target al metodo, ma questo è solo più la bruttezza)
Problemi correlati