getrecursiondepth

Manlio Perillo NOmanlio_perilloSPAM at libero.it
Thu Sep 30 19:59:04 CEST 2004


On Tue, 28 Sep 2004 16:26:16 GMT, Andrew Dalke <adalke at mindspring.com>
wrote:

>Manlio Perillo wrote:
>>>>1) To write code that execute once in a function (as C static
>>>>variables)
>>>>2) To guard against too many recursion
>
>> def spam(x):
>> 	if getrecursiondepth() == 1:
>> 		# initialization code
>> 
>> This is equivalent to C++ code:
>> 
>> struct Init
>> {
>> Init() { /* initialization code */ }
>> };
>> 
>> void spam(int x)
>> {
>> 	static Init init;
>> 	...
>> }
>
>No, it isn't.  It requires that spam() be called from
>the top-level code.  But what if it's called from
>the unittest framework?  Then the depth will be lower.

You are right. Thanks.

>
>Try this as a alternate solution for your style
>of use.  It's still not the right one because it
>doesn't handle reloads nor multiple functions
>created through exec's.
>
>_firsttime_db = {}
>def firsttime():
>   frame = sys._getframe(1)
>   tag = (frame.f_lineno, frame.f_code.co_filename)
>   if tag in _firsttime_db:
>     return 0
>   _firsttime_db[tag] = 1
>   return 1
>
> >>> def spam():
>...   if firsttime():
>...     print "Hello!"
>...   print "called"
>...
> >>> spam()
>Hello!
>called
> >>> spam()
>called
> >>> spam()
>called
> >>>
>

No, I don't want this. "Hello!" should be printed every times.

Here is a functions that returns True if the caller's 'recursion
depth' is 1.
Please check if this is correct.


>>> def firstlevel_call():
       return sys._getframe(1).f_code != sys._getframe(2).f_code

N.B.: sys._getframe(2) can raise an exception


An example:
>>> def foo(n = 0):
	print firstlevel_call()
	print 'n =', n
	if n == 5: return
	foo(n + 1)

>>> foo()
True
n = 0
False
n = 1
False
n = 2
False
n = 3
False
n = 4
False
n = 5



Using firstlevel_call one can 'rescale' the getrecursiondepth
function.
Here is the correct pystate module:

---------------------------
from _pystate import getrecursiondepth as _getrecursiondepth

_recursion_base = 0

def rescale(depth = None):
    global _recursion_base
    
    if depth is None:
        _recursion_base = _getrecursiondepth()
    else:
        _recursion_base = depth

       
def getrecursiondepth():
    return _getrecursiondepth() - _recursion_base

---------------------------

And here is an example:

>>> def foo(n = 0):
    if firstlevel_call():
	    pystate.rescale()

    print 'n = %s, recursion depth = %s' % (n,
pystate.getrecursiondepth())
    if n == 5: return
    foo(n + 1)



>>> foo()
n = 0, recursion depth = 0
n = 1, recursion depth = 1
n = 2, recursion depth = 2
n = 3, recursion depth = 3
n = 4, recursion depth = 4
n = 5, recursion depth = 5



>> I have already used this 'pattern'.
>> But sometimes I don't want to expose the 'limit' on the argument list.
>> Actually I have resolved this by doing:
>> 
>> def my_function(x, y, z, __max_depth = 20)
>> 
>> But this means I can't use keyword argument in my function!
>
>then do
>
>def _my_function(x, y, z, __maxdepth = 20):
>   .. do your recursive code here ..
>
>def my_function(x, y, z):
>   return _my_function(x, y, z)
>

Sorry, I don't understand.
Here is my_function:


def my_function(a, b, *args, **kwargs):
	print 'a, b, args, kwargs:', a, b, args, kwargs




Thanks and regards   Manlio Perillo



More information about the Python-list mailing list