Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Self function

Reply
Thread Tools

Self function

 
 
bearophileHUGS@lycos.com
Guest
Posts: n/a
 
      05-03-2009
Sometimes I rename recursive functions, or I duplicate&modify them,
and they stop working because inside them there's one or more copy of
their old name.
This happens to me more than one time every year.
So I have written this:

from inspect import getframeinfo, currentframe

def SOMEVERYUGLYNAME(n):
if n <= 1:
return 1
else:
self_name = getframeinfo(currentframe()).function
#self_name = getframeinfo(currentframe())[2] # older python

# only if it's a global function
#return n * globals()[self_name](n - 1)
return n * eval(self_name + "(%d)" % (n - 1))
assert SOMEVERYUGLYNAME(6) == 2*3*4*5*6

Are there nicer ways to do that? I don't know.
If there aren't, then a way may be added.
An idea-syntax:

def fact(n):
return 1 if n <= 1 else n * inspect.self(n - 1)

Or even a lambda, because you don't need the name anymore to call the
function:

fact = lambda n: 1 if n <= 1 else n * self(n - 1)

(If you have two or more recursive functions that call each other this
idea can't be used, but I think such situations are uncommon enough to
not deserve help from the language).

Bye,
bearophile
 
Reply With Quote
 
 
 
 
Emile van Sebille
Guest
Posts: n/a
 
      05-04-2009
On 5/3/2009 3:39 PM http://www.velocityreviews.com/forums/(E-Mail Removed) said...
> Sometimes I rename recursive functions, or I duplicate&modify them,
> and they stop working because inside them there's one or more copy of
> their old name.
> This happens to me more than one time every year.
> So I have written this:
>
> from inspect import getframeinfo, currentframe
>
> def SOMEVERYUGLYNAME(n):
> if n <= 1:
> return 1
> else:
> self_name = getframeinfo(currentframe()).function
> #self_name = getframeinfo(currentframe())[2] # older python
>
> # only if it's a global function
> #return n * globals()[self_name](n - 1)
> return n * eval(self_name + "(%d)" % (n - 1))
> assert SOMEVERYUGLYNAME(6) == 2*3*4*5*6
>
> Are there nicer ways to do that?


I've sometimes used classes like:


class SOMEVERYUGLYNAME:
def __call__(self,n):
if n<=1:
return 1
else:
return n*self.__class__()(n-1)

assert SOMEVERYUGLYNAME()(6) == 2*3*4*5*6


It's probably nicer (for some definition of nice), but I wouldn't say
it's nice.

Emile

 
Reply With Quote
 
 
 
 
Steve Howell
Guest
Posts: n/a
 
      05-04-2009
On May 3, 5:21*pm, Emile van Sebille <(E-Mail Removed)> wrote:
> On 5/3/2009 3:39 PM (E-Mail Removed) said...
>
>
>
> > Sometimes I rename recursive functions, or I duplicate&modify them,
> > and they stop working because inside them there's one or more copy of
> > their old name.
> > This happens to me more than one time every year.
> > So I have written this:

>
> > from inspect import getframeinfo, currentframe

>
> > def SOMEVERYUGLYNAME(n):
> > * * if n <= 1:
> > * * * * return 1
> > * * else:
> > * * * * self_name = getframeinfo(currentframe()).function
> > * * * * #self_name = getframeinfo(currentframe())[2] # older python

>
> > * * * * # only if it's a global function
> > * * * * #return n * globals()[self_name](n - 1)
> > * * * * return n * eval(self_name + "(%d)" % (n - 1))
> > assert SOMEVERYUGLYNAME(6) == 2*3*4*5*6

>
> > Are there nicer ways to do that?

>
> I've sometimes used classes like:
>
> class SOMEVERYUGLYNAME:
> * * *def __call__(self,n):
> * * * * *if n<=1:
> * * * * * * *return 1
> * * * * *else:
> * * * * * * *return n*self.__class__()(n-1)
>
> assert SOMEVERYUGLYNAME()(6) == 2*3*4*5*6
>
> It's probably nicer (for some definition of nice), but I wouldn't say
> it's nice.
>


Some of that could probably abstracted into a decorator maybe?
 
Reply With Quote
 
Arnaud Delobelle
Guest
Posts: n/a
 
      05-04-2009
(E-Mail Removed) writes:

> Sometimes I rename recursive functions, or I duplicate&modify them,
> and they stop working because inside them there's one or more copy of
> their old name.
> This happens to me more than one time every year.
> So I have written this:
>
> from inspect import getframeinfo, currentframe
>
> def SOMEVERYUGLYNAME(n):
> if n <= 1:
> return 1
> else:
> self_name = getframeinfo(currentframe()).function
> #self_name = getframeinfo(currentframe())[2] # older python
>
> # only if it's a global function
> #return n * globals()[self_name](n - 1)
> return n * eval(self_name + "(%d)" % (n - 1))
> assert SOMEVERYUGLYNAME(6) == 2*3*4*5*6
>
> Are there nicer ways to do that? I don't know.
> If there aren't, then a way may be added.
> An idea-syntax:
>
> def fact(n):
> return 1 if n <= 1 else n * inspect.self(n - 1)
>
> Or even a lambda, because you don't need the name anymore to call the
> function:
>
> fact = lambda n: 1 if n <= 1 else n * self(n - 1)
>
> (If you have two or more recursive functions that call each other this
> idea can't be used, but I think such situations are uncommon enough to
> not deserve help from the language).
>
> Bye,
> bearophile


Here's an idea:

>>> def bindfunc(f):

.... def boundf(*args, **kwargs):
.... return f(boundf, *args, **kwargs)
.... return boundf
....
>>> @bindfunc

.... def fac(self, n):
.... return 1 if n <= 1 else n * self(n - 1)
....
>>> fac(5)

120
>>> fac = bindfunc(lambda f, n: 1 if n <= 1 else n*f(n - 1))
>>> fac(5)

120

--
Arnaud



 
Reply With Quote
 
Chris Rebert
Guest
Posts: n/a
 
      05-04-2009
On Sun, May 3, 2009 at 11:29 PM, Arnaud Delobelle
<(E-Mail Removed)> wrote:
> (E-Mail Removed) writes:
>
>> Sometimes I rename recursive functions, or I duplicate&modify them,
>> and they stop working because inside them there's one or more copy of
>> their old name.
>> This happens to me more than one time every year.
>> So I have written this:
>>
>> from inspect import getframeinfo, currentframe
>>
>> def SOMEVERYUGLYNAME(n):
>> ┬* ┬* if n <= 1:
>> ┬* ┬* ┬* ┬* return 1
>> ┬* ┬* else:
>> ┬* ┬* ┬* ┬* self_name = getframeinfo(currentframe()).function
>> ┬* ┬* ┬* ┬* #self_name = getframeinfo(currentframe())[2] # older python
>>
>> ┬* ┬* ┬* ┬* # only if it's a global function
>> ┬* ┬* ┬* ┬* #return n * globals()[self_name](n - 1)
>> ┬* ┬* ┬* ┬* return n * eval(self_name + "(%d)" % (n - 1))
>> assert SOMEVERYUGLYNAME(6) == 2*3*4*5*6
>>
>> Are there nicer ways to do that? I don't know.
>> If there aren't, then a way may be added.
>> An idea-syntax:
>>
>> def fact(n):
>> ┬* ┬* return 1 if n <= 1 else n * inspect.self(n - 1)
>>
>> Or even a lambda, because you don't need the name anymore to call the
>> function:
>>
>> fact = lambda n: 1 if n <= 1 else n * self(n - 1)
>>
>> (If you have two or more recursive functions that call each other this
>> idea can't be used, but I think such situations are uncommon enough to
>> not deserve help from the language).
>>
>> Bye,
>> bearophile

>
> Here's an idea:
>
>>>> def bindfunc(f):

> ... ┬* ┬* def boundf(*args, **kwargs):
> ... ┬* ┬* ┬* ┬* return f(boundf, *args, **kwargs)
> ... ┬* ┬* return boundf
> ...
>>>> @bindfunc

> ... def fac(self, n):
> ... ┬* ┬* return 1 if n <= 1 else n * self(n - 1)
> ...
>>>> fac(5)

> 120
>>>> fac = bindfunc(lambda f, n: 1 if n <= 1 else n*f(n - 1))
>>>> fac(5)

> 120


Why am I reminded of the Y-Combinator...?

Cheers,
Chris
--
http://blog.rebertia.com
 
Reply With Quote
 
bearophileHUGS@lycos.com
Guest
Posts: n/a
 
      05-04-2009
Arnaud Delobelle:
> >>> def bindfunc(f):

> ... * * def boundf(*args, **kwargs):
> ... * * * * return f(boundf, *args, **kwargs)
> ... * * return boundf


> ...>>> @bindfunc
> ... def fac(self, n):
> ... * * return 1 if n <= 1 else n * self(n - 1)
> ...>>> fac(5)
> 120


This is cute, now I have two names to take care of.
Thank you to all the people that have answered.
Another possible syntax:

def fact(n):
return 1 if n <= 1 else n * return(n - 1)

But I guess most people don't see this problem as important&common
enough to justify changing the language.

Bye,
bearophile
 
Reply With Quote
 
BJ÷rn Lindqvist
Guest
Posts: n/a
 
      05-04-2009
2009/5/4 <(E-Mail Removed)>:
> An idea-syntax:
>
> def fact(n):
> * *return 1 if n <= 1 else n * inspect.self(n - 1)
>
> Or even a lambda, because you don't need the name anymore to call the
> function:
>
> fact = lambda n: 1 if n <= 1 else n * self(n - 1)


How would it work with methods?

class Foo:
def fac(self, n):
return 1 if n <= 1 else n * self.self(n-1)

??


--
mvh Bj÷rn
 
Reply With Quote
 
Steve Howell
Guest
Posts: n/a
 
      05-04-2009
On May 3, 3:39*pm, (E-Mail Removed) wrote:
> Sometimes I rename recursive functions, or I duplicate&modify them,
> and they stop working because inside them there's one or more copy of
> their old name.
> This happens to me more than one time every year.
> So I have written this:
>
> from inspect import getframeinfo, currentframe
>
> def SOMEVERYUGLYNAME(n):
> * * if n <= 1:
> * * * * return 1
> * * else:
> * * * * self_name = getframeinfo(currentframe()).function
> * * * * #self_name = getframeinfo(currentframe())[2] # older python
>
> * * * * # only if it's a global function
> * * * * #return n * globals()[self_name](n - 1)
> * * * * return n * eval(self_name + "(%d)" % (n - 1))
> assert SOMEVERYUGLYNAME(6) == 2*3*4*5*6
>
> Are there nicer ways to do that? I don't know.
> If there aren't, then a way may be added.
> An idea-syntax:
>
> def fact(n):
> * * return 1 if n <= 1 else n * inspect.self(n - 1)
>
> Or even a lambda, because you don't need the name anymore to call the
> function:
>
> fact = lambda n: 1 if n <= 1 else n * self(n - 1)
>
> (If you have two or more recursive functions that call each other this
> idea can't be used, but I think such situations are uncommon enough to
> not deserve help from the language).
>


One very simple thing that you can do is assign the current function
name to a local var at the very top to make it a little more obvious.

I agree that there are lots of recursive patterns where python itself
does not provide much sugar. A pattern that comes up for me
occasionally is two methods with almost identical names, where one
function is the public interface and then another method that does
most of the recursion.
 
Reply With Quote
 
bearophileHUGS@lycos.com
Guest
Posts: n/a
 
      05-04-2009
Steve Howell:
>two methods with almost identical names, where one function is the public interface and then another method that does most of the recursion.<


Thanks Guido & Walter both Python and D support nested functions, so
in such situations I put the recursive function inside the "public
interface" function/method.

Recursion is a high-level way to represent certain kinds of algorithms
in a short and readable way (when data structures are nested, the most
natural algorithms that work on them are recursive). But in Python
function calls are slow, the maximum level of nested calls is limited
(and it can't grow too much), so this has sometimes forced me to
manually convert recursive functions into iterative ones with a stack.
This is silly for a supposed high-level language. The bad support for
recursivity is one of the few faults of Python.

Bye,
bearophile
 
Reply With Quote
 
Arnaud Delobelle
Guest
Posts: n/a
 
      05-04-2009
(E-Mail Removed) writes:

> Steve Howell:
>>two methods with almost identical names, where one function is the
>>public interface and then another method that does most of the
>>recursion.<

>
> Thanks Guido & Walter both Python and D support nested functions, so
> in such situations I put the recursive function inside the "public
> interface" function/method.


Yes, this is a common idiom for me:

def public_function(a, b):
def rec():
...
return rec()

E.g, to continue with the factorial toy example (of course for this
particular example and in this particular language, a loop would be more
appropriate):

def fac(n):
def rec(n, acc):
if n <= 1:
return acc
else:
return rec(n - 1, n*acc)
return rec(n, 1)

This is tail recursive, but Python does not optimise tail-calls so there
is not much point.

> Recursion is a high-level way to represent certain kinds of algorithms
> in a short and readable way (when data structures are nested, the most
> natural algorithms that work on them are recursive). But in Python
> function calls are slow, the maximum level of nested calls is limited
> (and it can't grow too much), so this has sometimes forced me to
> manually convert recursive functions into iterative ones with a stack.
> This is silly for a supposed high-level language. The bad support for
> recursivity is one of the few faults of Python.


Bearophile, there is a thread on python-ideas about tail-call
optimization at the moment.

--
Arnaud
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Changing self: if self is a tree how to set to a different self Bart Kastermans Python 6 07-13-2008 11:19 AM
__autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) falcon Python 0 07-31-2005 05:41 PM
Re: __autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) Ralf W. Grosse-Kunstleve Python 2 07-12-2005 03:20 AM
Proposal: reducing self.x=x; self.y=y; self.z=z boilerplate code Ralf W. Grosse-Kunstleve Python 16 07-11-2005 09:28 PM
__autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) Ralf W. Grosse-Kunstleve Python 18 07-11-2005 04:01 PM



Advertisments