How to get function string name from i-th stack position?

D

dmitrey

hi all,
how to get string name of a function that is n levels above the
current Python interpreter position?

Thank you in advance, D.
 
T

Tim Chase

how to get string name of a function that is n levels above
the current Python interpreter position?

Use the results of traceback.extract_stack()

from traceback import extract_stack
def one(x):
print "one", x
stk = extract_stack()
for mod, lineno, fun_name, call_code_text in stk:
print "[%s:%i] in %s" % (mod, lineno, fun_name)
def two(x):
print "two", x
one(x)
def three(x):
print "three", x
two(x)
three("Hi")


-tkc
 
D

dmitrey

how to get string name of a function that is n levels above
the current Python interpreter position?

Use the results of traceback.extract_stack()

   from traceback import extract_stack
   def one(x):
     print "one", x
     stk = extract_stack()
     for mod, lineno, fun_name, call_code_text in stk:
       print "[%s:%i] in %s" % (mod, lineno, fun_name)
   def two(x):
     print "two", x
     one(x)
   def three(x):
     print "three", x
     two(x)
   three("Hi")

-tkc

Thank you. And what should I do to get function by itself instead of
its string name, e.g. I want to know does this function is my_func or
any other? For example, I would like to check is this function Python
sum(), or maybe numpy.sum(), or anything else?
Regards, D.
 
I

Ian Kelly

Thank you. And what should I do to get function by itself instead of
its string name, e.g. I want to know does this function is my_func or
any other? For example, I would like to check is this function Python
sum(), or maybe numpy.sum(), or anything else?

The Python stack only includes Python code objects. Built-ins like
sum won't appear in it because they're basically C functions and don't
have associated code objects. If you really want to see them, you
could probably do something with ctypes to inspect the C stack, but I
don't recommend it.

You can get the Python code objects from the stack by calling
inspect.stack(), which includes each frame object currently on the
stack as the first member of each tuple. E.g.:

frames = map(operator.itemgetter(0), inspect.stack())

Each frame has an f_code attribute that stores the code object
associated with that frame. Getting the actual function from the code
object is tricky, for two reasons. One, not all code objects
represent functions. There are also code objects for modules, class
definitions, and probably other thing as well. Two, code objects
don't have associated functions. The relationship is the reverse:
functions have associated code objects. You would have to iterate
over each function that you're interested in, looking for one with a
func_code attribute that "is" the frame's f_code attribute.

In any case, testing function identity is a rather large rabbit hole
that is best avoided. These are mathematically the same function:

def plus1(value):
return value + 1

plus_one = lambda x: x + 1

But they are two distinct function objects, and there is no way
programmatically to determine that they are the same function except
by comparing the bytecode (which won't work generally because of the
halting problem).

What is it that you're trying to do? Perhaps the helpful folks on the
list will be able to suggest a better solution if you can provide more
details.

Cheers,
Ian
 
D

dmitrey

The Python stack only includes Python code objects.  Built-ins like
sum won't appear in it because they're basically C functions and don't
have associated code objects.  If you really want to see them, you
could probably do something with ctypes to inspect the C stack, but I
don't recommend it.

You can get the Python code objects from the stack by calling
inspect.stack(), which includes each frame object currently on the
stack as the first member of each tuple.  E.g.:

frames = map(operator.itemgetter(0), inspect.stack())

Each frame has an f_code attribute that stores the code object
associated with that frame.  Getting the actual function from the code
object is tricky, for two reasons.  One, not all code objects
represent functions.  There are also code objects for modules, class
definitions, and probably other thing as well.  Two, code objects
don't have associated functions. The relationship is the reverse:
functions have associated code objects.  You would have to iterate
over each function that you're interested in, looking for one with a
func_code attribute that "is" the frame's f_code attribute.

In any case, testing function identity is a rather large rabbit hole
that is best avoided.  These are mathematically the same function:

def plus1(value):
    return value + 1

plus_one = lambda x: x + 1

But they are two distinct function objects, and there is no way
programmatically to determine that they are the same function except
by comparing the bytecode (which won't work generally because of the
halting problem).

What is it that you're trying to do?  Perhaps the helpful folks on the
list will be able to suggest a better solution if you can provide more
details.

Cheers,
Ian

Maybe it is somehow possible to compare function id with my candidates
id, e.g.
PythonSumID = id(sum)
import numpy
NumpySumID = id(numpy.sum)
func = getting_function_from_Nth_stack_level_above
if id(func) == PythonSumID:
....
elif id(func) == NumpySumID:
....
else:
....
I need it due to the following reason: FuncDesigner users often use
Python or numpy sum on FuncDesigner objects, while FuncDesigner.sum()
is optimized for this case, works faster and doesn't lead to "Max
recursion dept exceeded", that sometimes trigger for numpy or Python
sum() when number of summarized elements is more than several
hundreds. I would like to print warning "you'd better use FuncDesigner
sum" if this case has been identified.
Regards, D.
 
L

Lie Ryan

But they are two distinct function objects, and there is no way
programmatically to determine that they are the same function except
by comparing the bytecode (which won't work generally because of the
halting problem).

Actually, it is often possible to determine that two functions are the
same function, you simply need a to compare whether the function object
lives in the same memory address. It is also possible to determine if
two functions are different, if the function object are in different
memory address than the function is different function.

What is difficult to do due to the Halting problem is comparing whether
two different functions are "equivalent" (and therefore interchangeable).

I think the OP wants to find the former, not the latter. The former is
trivial, the latter impossible.
 
I

Ian Kelly

Actually, it is often possible to determine that two functions are the same
function, you simply need a to compare whether the function object lives in
the same memory address. It is also possible to determine if two functions
are different, if the function object are in different memory address than
the function is different function.

What is difficult to do due to the Halting problem is comparing whether two
different functions are "equivalent" (and therefore interchangeable).

Yes, that is what I said. You can determine whether two function
objects are the same, but not whether they are *mathematically* the
same function.
I think the OP wants to find the former, not the latter. The former is
trivial, the latter impossible.

Based on his subsequent clarification, I agree, although from his
original post it sounded like he was just trying to identify summing
functions in general. However, finding the built-in sum function on
the stack is not trivial at all, perhaps not even possible.
 
I

Ian Kelly

Maybe it is somehow possible to compare function id with my candidates
id, e.g.
PythonSumID = id(sum)
import numpy
NumpySumID = id(numpy.sum)
func = getting_function_from_Nth_stack_level_above
if id(func) == PythonSumID:
 ....
elif id(func) == NumpySumID:
 ....
else:
 ....
I need it due to the following reason: FuncDesigner users often use
Python or numpy sum on FuncDesigner objects, while FuncDesigner.sum()
is optimized for this case, works faster and doesn't lead to "Max
recursion dept exceeded", that sometimes trigger for numpy or Python
sum() when number of summarized elements is more than several
hundreds. I would like to print warning "you'd better use FuncDesigner
sum" if this case has been identified.

The only think I can think of would be to replace the sum built-in
with a wrapper that checks whether it's being called on FuncDesigner
objects and issues a warning. Users might not like you messing with
their built-ins in that way, though.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top