[Python-Dev] Function Operators

Thomas Jollans thomas at jollans.com
Sun Jul 18 19:43:44 CEST 2010


On 07/18/2010 05:52 PM, Reid Kleckner wrote:
> Usual disclaimer: python-dev is for the development *of* python, not
> *with*.  See python-list, etc.

Moving to python-list. Please keep discussion there.

> 
> That said, def declares new functions or methods, so you can't put
> arbitrary expressions in there like type(f).__mul__ .
> 
> You can usually assign to things like that though, but in this case
> you run into trouble, as shown below:
> 
>>>> def func(): pass
> ...
>>>> type(func)
> <class 'function'>
>>>> def compose(f, g):
> ...     return lambda x: f(g(x))
> ...
>>>> type(func).__mul__ = compose
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: can't set attributes of built-in/extension type 'function'
> 
> As the interpreter says, it doesn't like people mucking with operator
> slots on built in types.
> 
> Finally, if you like coding in that very functional style, I'd
> recommend Haskell or other ML derived languages.  Python doesn't
> support that programming style very well by choice.
> 
> Reid
> 
> On Sun, Jul 18, 2010 at 8:34 AM, Christopher Olah
> <christopherolah.co at gmail.com> wrote:
>> Dear python-dev,
>>
>> In mathematical notation, f*g = z->f(g(z)) and f^n = f*f*f... (n
>> times). I often run into situations in python where such operators
>> could result in cleaner code. Eventually, I decided to implement it
>> myself and see how it worked in practice.
>>
>> However, my intuitive implementation [1] doesn't seem to work. In
>> particular, despite what it says in function's documentation, function
>> does not seem to be in __builtin__. Furthermore, when I try to
>> implement this through type(f) (where f is a function) I get invalid
>> syntax errors.
>>
>> I hope I haven't made some trivial error; I'm rather inexperienced as
>> a pythonist.
>>
>> Christopher Olah
>>
>>
>> [1] Sketch:
>>
>> def __builtin__.function.__mul__(self, f):
>>    return lambda x: self(f(x))
>>
>> def __builtin__.function.__pow__(self, n):
>>    return lambda x: reduce(lambda a,b: [f for i in range(n)]+[x])


As Reid explained, you can't just muck around with built-in types like
that. However, you can "use a different type".

If you're not familiar with Python decorators, look them up, and then
have a look at this simple implementation of what you were looking for:

>>> class mfunc:
...     def __init__(self, func):
...         self.func = func
...         self.__doc__ = func.__doc__
...         self.__name__ = func.__name__
...     def __call__(self, *args, **kwargs):
...         return self.func(*args, **kwargs)
...     def __mul__(self, f2):
...         @mfunc
...         def composite(*a, **kwa):
...             return self.func(f2(*a, **kwa))
...         return composite
...     def __pow__(self, n):
...         if n < 1:
...             raise ValueError(n)
...         elif n == 1:
...             return self.func
...         else:
...             return self * (self ** (n-1))
...
>>> @mfunc
... def square(x): return x*x
...
>>> @mfunc
... def twice(x): return 2*x
...
>>> (square*twice)(1.5)
9.0
>>> addthree = mfunc(lambda x: x+3)
>>> addfifteen = (addthree ** 5)
>>> addfifteen(0)
15
>>>




More information about the Python-Dev mailing list