2010-11-04 29 views
8

Ho cercato ovunque ma è un argomento difficile da cercare senza molto rumore. Voglio fare qualcosa di simile:Come aggiungere funzioni

def f(arg): 
    return arg * arg 

def add(self, other): 
    return self * other 

f.__add__ = add 

cubefunction = f + f 

Ma ho errori sul compito di cubefunction come:

TypeError: unsupported operand type(s) for +: 'function' and 'function' 

C'è alcuna funzione di algebra possibile in pitone o sto solo facendo un errore stupido?

edit: molto più tardi, stavo leggendo intro ufficiale di Python per la programmazione funzionale (http://docs.python.org/howto/functional.html), e verso il basso si fa riferimento a un terzo pacchetto partito "funzionale" (http://oakwinter.com/code/functional/documentation/), che può comporre funzioni, vale a dire:

>>> from functional import compose 
>>> def add(a, b): 
...  return a + b 
... 
>>> def double(a): 
...  return 2 * a 
... 
>>> compose(double, add)(5, 6) 
22 
+0

Tuttavia, il tuo esempio sembra indicare che desideri aumentare un valore per la quarta potenza, non per il cubo. –

+0

Immagino che + significhi essere la composizione "gof" della funzione? (Non è utile per una risposta a * overloading + su un oggetto funzione *). –

+0

Oops, intendo '(f + g) (x) ==> f (g (x))' ... comunque, voglio assicurarmi che il -intent- sia chiaro. C'è già una risposta che mostra una tecnica di utilizzo di un tipo/wrapper intermedio. –

risposta

6

non credo che si può fare questo. Tuttavia, utilizzando il metodo magico __call__ consente di definire la propria classe callable che agisce come una funzione e su cui si può definire __add__:

>>> class FunctionalFunction(object): 
...  def __init__(self, func): 
...    self.func = func 
... 
...  def __call__(self, *args, **kwargs): 
...    return self.func(*args, **kwargs) 
... 
...  def __add__(self, other): 
...    def summed(*args, **kwargs): 
...      return self(*args, **kwargs) + other(*args, **kwargs) 
...    return summed 
... 
...  def __mul__(self, other): 
...    def composed(*args, **kwargs): 
...      return self(other(*args, **kwargs)) 
...    return composed 
... 
>>> triple = FunctionalFunction(lambda x: 3 * x) 
>>> times_six = triple + triple 
>>> times_six(2) 
12 
>>> times_nine = triple * triple 
>>> times_nine(3) 
27 

Qui + è sovraccarico di oltre puntuale, e * alla composizione. Certo, puoi fare tutto quello che vuoi.


Interessante domanda per i guru Python: perché non funziona il seguente (incisivo sporco anche se lo è)?

>>> from types import MethodType, FunctionType 
>>> f = lambda: None 
>>> f.__add__ = MethodType(lambda self, other: "summed!", f, FunctionType) 
>>> f.__add__(f) 
'summed!' 
>>> f + f 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'function' and 'function' 
+1

+1 per mostrare utilizzando un tipo intermedio e \ __ call__. Tuttavia, credo '(f + g) (x) ==> f (g (x))' - cioè, composizione della funzione. –

+1

@pst: heh questa è una notazione icky. Ho aggiunto in composizione per l'OP. – katrielalex

+1

@ pst Sì, katriealex ha perfettamente ragione. Le funzioni sono generalmente considerate come un anello. '+' è universalmente aggiunta puntuale. '*' può essere sia la moltiplicazione puntuale _or_ composizione (ove possibile). – aaronasterling

1

penso che quello che vuoi dire fare è:

cubefunction = (lambda x: add(f(x), f(x))) 
+6

No, penso che quello che sta cercando di fare è definire '__add__' sulle funzioni. – katrielalex

1

Nel codice, f deve essere una classe, non una funzione. Se si dispone di una classe, è possibile implementare un metodo aggiungere (autonomo, altro) che sovraccaricherà l'operatore +.

1

Beh, penso di avere qualcosa di interessante da aggiungere funzioni. Riguarda la funzione lambda e potrebbe risolvere il tuo problema.Almeno è fissato miniera:

>>> def func(x) : 
>>>  return x 
>>> 
>>> f = lambda x : func(x) 
>>> sum_of_f = [ f for i in range(5) ] 
>>> F = lambda x : sum([ i(x) for i in sum_of_f ]) 
>>> F(1) 
5 
>>> F(2) 
10 

e per coloro che sono interessati a passare parametri

>>> def func(x, p) : 
>>>  return x * p 
>>> 
>>> param = [ 0, 1, 2, 3, 4 ] 
>>> 
>>> f = lambda x, p : func(x, p) 
>>> sum_of_f = [ f for i in range(5) ] 
>>> F_bis = lambda x : sum([ sum_of_f[i](x, param[i]) for i in range(5) ]) 
>>> F_bis(1) 
10 
>>> F_bis(2) 
20 
1

Un po 'in ritardo, ma questo tipo di algebra può essere fatto facilmente usando le funzioni lambda:

>>> f = lambda x: x*x 
>>> g = lambda x: x*x 
>>> h = lambda x: f(g(x)) 
>>> h(2) 
16 
>>> j = lambda x: f(x) + g(x) 
>>> j(2) 
8 
>>> 

(f e g non devono essere funzioni lambda)

Si possono fare tutti i tipi di cose interessanti con questo. Supponiamo che tu voglia definire la funzione f(x) = 1 + x + x**2 + ... + x**n per un dato n. Si può fare:

>>> n = 3 
>>> f = lambda x: 1 
>>> for i in range(n): 
...  f = lambda x, j = i + 1, k = f: k(x) + x**j 
... 
>>> f(2) 
15 

per capire il motivo per cui ho fatto la lambda in questo modo (lambda x, j = i + 1, k = f:) è meglio leggere questo: https://docs.python.org/3.5/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result

Per farla breve: i parametri in una funzione lambda non hanno una copia locale . Se avessi usato il i dal ciclo come in lambda x, k = f: k(x) + x**(i + 1), avremmo avuto la funzione f(x) = 1 + x**3 + x**3 + x**3.

Problemi correlati