2013-02-22 13 views
6

in questo momento sto usando chiusure per generare funzioni come in questo esempio semplificato:Genera funzioni senza chiusure in Python

def constant_function(constant): 
    def dummyfunction(t): 
     return constant 
    return dummyfunction 

Queste funzioni generati vengono quindi passati al init-metodo di una classe personalizzata che li memorizza come attributi di istanza. Lo svantaggio è che rende le istanze di classe spiacevoli. Quindi mi chiedo se esiste un modo per creare generatori di funzioni evitando chiusure.

+0

Le classi chiamabili possono essere un'opzione, sebbene vengano fornite con il proprio insieme di avvertimenti e complessità. –

risposta

8

Si potrebbe utilizzare una classe callable:

class ConstantFunction(object): 
    def __init__(self, constant): 
     self.constant = constant 
    def __call__(self, t): 
     return self.constant 

def constant_function(constant): 
    return ConstantFunction(constant) 

Lo stato di chiusura della vostra funzione è poi trasferito a un'istanza di attributo, invece.

+0

In Python 3.3, il pickling di una lambda mi dà '_pickle.PicklingError: Can not pickle : attribute lookup builtins.function failed'. (Il decapaggio delle funzioni regolari con un nome funziona, ma si riferisce solo al nome e al modulo di quella funzione.) – delnan

+0

@delnan: hrmz, lambdas anonimi devono essere caricabili come funzioni, appare. Rimosso l'opzione per ora. –

+1

@delnan: Si scopre che ho letto male [questa domanda] (http://stackoverflow.com/questions/11878300/serializing-and-deserializing-lambdas) e quindi ho pensato che lambda avrebbe funzionato. :-) –

0

Non che lo raccomando per uso generale ... ma esiste un approccio alternativo alla compilazione e al codice exec. Sta generando una funzione senza chiusura.

>>> def doit(constant): 
... constant = "def constant(t):\n return %s" % constant 
... return compile(constant, '<string>', 'exec') 
... 
>>> exec doit(1) 
>>> constant(4) 
1 
>>> constant 

Nota che per fare questo all'interno di una funzione di inclusione o di classe (cioè non nel namespace globale) si deve passare anche nello spazio dei nomi appropriato per exec. Vedere: https://docs.python.org/2/reference/simple_stmts.html#the-exec-statement

C'è anche il doppio approccio lambda, che non è davvero una chiusura, beh, una sorta di ...

>>> f = lambda x: lambda y:x 
>>> g = f(1) 
>>> g(4) 
1 
>>> import dill 
>>> _g = dill.dumps(g) 
>>> g_ = dill.loads(_g) 
>>> g_(5) 
1 

Mi sembravi preoccupato per la capacità di salamoia oggetti di chiusura simile, in modo da puoi vedere anche i doppi lambda che sono disponibili solo se usi dill. Lo stesso per le istanze di classe.