Forum >> Principianti >> funzioni dinamiche che utilizzano la parola chiave self

Pagina: 1

Buongiorno a tutti, premesso che sono abbastanza un neofita di python, vi sottopongo il seguente quesito, chiedendovi sia perchè non funziona e anche qual è la strada più pythonica per ottenere quello che voglio fare.
Se scrivo il seguente codice:

class prova:
	def __init__(self,a):
		self.a = a
		self.f = None
	def impostaFunzione(self,f):
		self.f = f
	
poi vorrei che a runtime io potessi assegnare delle funzioni che manipolino self.a

Ma se la funzione che imposto è:

def g(x):
	return x + 1
allora quando eseguo

z = prova(5)
z.impostaFunzione(g)
z.f(8)
Mi ritorna correttamente 9

Io però vorrei poter assegnare una funzione tipo:

def g(x):
	return self.a + x
ma se poi imposto

z.impostaFunzione(g)
z.f(8)
ottengo il seguente errore:

NameError: global name 'self' is not defined




Come devo fare?

Grazie a tutti
La funzione 'g' è definita nel blocco principale del programma e non può conoscere il valore di 'self', a meno che questo non le venga passato durante la chiamata (ad esempio attraverso un parametro aggiuntivo di nome 'context'). L'unico punto in cui 'self' esiste ed ha un valore è nei metodi della classe, quindi a 'self.f' non si può assegnare direttamente la funzione 'g', ma si deve assegnare una nuova funzione (creata al volo all'interno del metodo) che si incarichi di aggiungere alla chiamata di 'g' il valore di 'self'. Nell'esempio seguente questa nuova funzione è costruita tramite un'espressione lambda:
class prova:

    def __init__(self, a):
        self.a = a
        self.f = None

    def impostaFunzione(self, f):
        self.f = lambda *arg, **kw: f(self, *arg, **kw)


def g(context, x):
    return context.a + x


z = prova(5)
z.impostaFunzione(g)
z.f(8)

In realtà c'è un'altra possibilità, però mi sembra meno chiara. Visto che 'self' all'interno dei metodi corrisponde a 'z' nel blocco principale, allora si può passare direttamente 'z' al parametro 'context' di 'g':
class prova:

    def __init__(self, a):
        self.a = a
        self.f = None

    def impostaFunzione(self, f):
        self.f = f


def g(context, x):
    return context.a + x


z = prova(5)
z.impostaFunzione(g)
z.f(z, 8)



--- Ultima modifica di Claudio_F in data 2016-03-26 18:15:46 ---
*** Il codice va evidenziato con il simbolo di fianco ai colori per non perdere l'indentazione ***
Spettacolare, nella tua semplicità mi hai illuminato su un paio di cose che proprio fino a ora non avevo capito, grazie mille!
un paio di cose che proprio fino a ora non avevo capito
Una di queste immagino sia il fatto che 'self' non è una parola chiave ma solo il nome convenzionale dato al parametro che si riferisce all'istanza della classe su cui il metodo deve lavorare. In effetti si può dare qualsiasi nome:
class prova:

    def __init__(me_medesimo, a):
        me_medesimo.a = a
        me_medesimo.f = None

    def impostaFunzione(me_medesimo, f):
        me_medesimo.f = lambda *arg, **kw: f(me_medesimo, *arg, **kw)
Il fatto che sia un semplice parametro si vede anche dal modo alternativo di chiamata dei metodi, le due righe seguenti sono identiche (ma nella seconda il passaggio di 'z' è scritto in modo esplicito):
z.impostaFunzione(g)
prova.impostaFunzione(z, g)

*** Il codice va evidenziato con il simbolo di fianco ai colori per non perdere l'indentazione ***
e' così in effetti...
Inoltre ho avuto la scusa per imparare una volta per tutte il passaggio di parametri tramite * e ** ;)


Pagina: 1



Esegui il login per scrivere una risposta.