Prev: why is this group being spammed?
Next: Fascinating interview by Richard Stallman at KTH on emacs historyand internals
From: Thomas Jollans on 18 Jul 2010 13:43 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(a)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 >>>
From: Christopher Olah on 18 Jul 2010 14:48 Firstly, apologies for posting to the wrong list. Since I was fiddling around with a modification to the language, if the implementation details of something I'd never expect to get accepted, I'd thought python-dev might be appropriate... In retrospect, it is fairly clear that it was the wrong choice. Secondly, the problem with using decorators is that it doesn't make it so that all functions do this by default. If one is going to decorate every function they use/declare, lambdas look preferable. In any case, thank you for your help. Christopher On Sun, Jul 18, 2010 at 1:43 PM, Thomas Jollans <thomas(a)jollans.com> wrote: > 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(a)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 >>>> > > >
From: Terry Reedy on 18 Jul 2010 15:10
>> Christopher Olah >>> 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. Python has a general mechanism for composing functions to make new functions: the def statement. "z = f*g" is a special case operation combining two compatible one-parameter parameter functions. In Python, it is spelled def z(x): return f(g(x)) The advantage of the latter is that it gives the resulting function object a definition name attached to the function as an attribute, which is important for error tracebacks. This gets to a difference between math and computing. In math, 'z=f*f', if it is not an equality claim ('z==f*g' in Python terms), defines 'z' to mean the *pre-existing*, abstract, attribute-less function that can also be denoted by 'f*g'. In Python (in particular), it would mean "create a *new*, anonymous function object and associate it non-exclusively with 'z'". If f and g are not primitive functions but are compositions themselves, then substituting the composition for g in the composition for f may allow for simplification and greater efficiency. This consideration is irrelevant in math, where computation happens instantaneously, or where f*g is simply a set of ordered pairs, just like f and g (all with instataneous lookup). As for f^n, it is very rare in practice for n to be a fixed value more than 2 or 3. For n==2, f^2 is simply f*f, see above. For n==3, def f3(x): return f(f(f(x))) has the advantage of creating one new function instead of two. I believe larger values of n mostly arise in iteration to a fixed point or until some other stopping point in reached. Terry Jan Reedy |