Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Find function name in function

2 views
Skip to first unread message

Ilariu Raducan

unread,
May 20, 2003, 10:04:46 AM5/20/03
to
Hi,

Is it possible to find the function name in that specific function?
I the following example I want to be able to find what name the user
used to call the function: XXX, yy, zz
Is that possible?

def XXX():
#find function name XXX or yy
pass
XXX()
yy=XXX
yy()
zz=XXX
zz()

Thank you,
Lale

Terry Reedy

unread,
May 20, 2003, 11:17:52 AM5/20/03
to

"Ilariu Raducan" <la...@fotonation.com> wrote in message
news:5Cqya.14237$pK2....@news.indigo.ie...

> Is it possible to find the function name in that specific function?

In CPython, it is possible to get a handle on a function from within a
function and from that gets its *definition* name (the one in the def
statement), but you are asking about the names bound to the function
..

> I the following example I want to be able to find what name the user
> used to call the function: XXX, yy, zz
> Is that possible?

I do not believe this is sanely possible. (Insanely would be getting
the code and line number of the calling context, decompiling the code
and using the linenum to find the call and from that the calling name,
if there is one.

> def XXX():
> #find function name XXX or yy
> pass
> XXX()
> yy=XXX
> yy()
> zz=XXX
> zz()

You left out the possibility of calling a function without a name or
without it even having any bound names left.

def f(): print 'hi'

fl = [f]
del f
fl[0]()
# prints
hi

Terry J. Reedy


Sean Ross

unread,
May 20, 2003, 11:12:22 AM5/20/03
to
Hi.

"Ilariu Raducan" <la...@fotonation.com> wrote in message
news:5Cqya.14237$pK2....@news.indigo.ie...

> Is it possible to find the function name in that specific function?
> I the following example I want to be able to find what name the user
> used to call the function: XXX, yy, zz
> Is that possible?

Not exactly. You can find the name of the function, 'XXX', but not the name
of the referencer, 'yy' or 'zz', with this:

# credit Alex Martelli, "Python Cookbook" p. 440
def whoami():
"returns name of calling function"
import sys
return sys._getframe(1).f_code.co_name

def XXX():
print whoami()

XXX()
yy=XXX
yy()
zz=XXX
zz()

This outputs:
XXX
XXX
XXX


Or, you can get the source line where this function is called:

def howamicalled():
"returns source line where calling function is called"
import inspect
return inspect.stack()[2][-2][0].strip()

def XXX():
print howamicalled()

XXX()
yy=XXX
yy()
zz=XXX
zz()

which outputs:
XXX()
yy()
zz()

This seems useful until you do something like the following:

print "%s %s"%(yy(), zz())

Now, this will output:

print "%s %s"%(yy(), zz())
print "%s %s"%(yy(), zz())

At which point I do not think you can reliably isolate which function was
the one being called. For instance, we can define a new function

def foo():
pass

and

print "%s %s"%(yy(), foo())

will output:

print "%s %s"%(yy(), foo())

But, which function is a referencer to XXX?

So, the answer to your question is, "No, I don't think so"

Hope this helped,
Sean

Gerrit Holl

unread,
May 20, 2003, 11:58:18 AM5/20/03
to
Ilariu Raducan schreef op dinsdag 20 mei om 16:08:10 +0000:

> Is it possible to find the function name in that specific function?

It is, but why do you need it?
Using tracebacks you can do it...

It's quite difficult, but if you want I can find it out for you.

I think I did it once...

yours,
Gerrit.

--
208. If he was a freed man, he shall pay one-third of a mina.
-- Hammurabi, Code of Law
--
Asperger Syndroom - een persoonlijke benadering:
http://people.nl.linux.org/~gerrit/
Het zijn tijden om je zelf met politiek te bemoeien:
http://www.sp.nl/

Sean Ross

unread,
May 20, 2003, 1:21:19 PM5/20/03
to
Here's something that gets you a little bit closer to what you're looking
for, however, you will notice that it does not resolve the issue presented
in my previous posting. I.e., if you have two (or more) aliases to a
function and you call them in the same line of code, WhoMightIBe() cannot
determine which of the aliases was used, it can only tell you that the list
of possible aliases.


def WhoMightIBe():
"returns name and/or possible alias' of called calling function"
import inspect, re
stack = inspect.stack()
# get name of function as listed in def statement
defname = eval(stack[1][-3])
# get the source line where function is called
srcline = stack[2][-2][0].strip()
# extract function names from source line (robust? ...doubtful)
pattern = re.compile(r'[a-z,A-Z,0-9,_]+\(')
matches = [txt.replace('(','') for txt in pattern.findall(srcline)]
# see which function name(s) alias(es) our target function
possibles = [funcname for funcname in matches if eval(funcname) is
defname]
return possibles

def XXX():
print WhoMightIBe()

XXX()
yy=XXX
a= yy()
zz=XXX
zz()

print "%s %s"%(yy(), zz())

#outputs:
['XXX']
['yy']
['zz']
['yy', 'zz']
['yy', 'zz']
None None


Sean Ross

unread,
May 20, 2003, 3:15:42 PM5/20/03
to
Okay, here you go...This function will identify the called functions name by
it's proper name or by it's alias, however it's being called. It grabs the
frame where the function was called, gets the associated code object and
last instruction index, disassembles the code object, isolates the
instruction, and slices out the function name. I don't know if this is
robust, dangerous, or whatever, but it does what you're asking for.

def whoami2():
"returns name of called calling function"
import sys, dis

# get frame where calling function is called
frame = sys._getframe(2)

# get code and next to last instruction from frame
code = frame.f_code
lasti = frame.f_lasti-3

# redirect ouput of disassemble (stdout)
oldout = sys.stdout
sys.stdout = open('log','w')
dis.disassemble(code, lasti)
sys.stdout.close()

# restore stdout
sys.stdout = oldout

fd = open('log')

# retrieve current byte code line
current = [line for line in fd.readlines() if line.startswith('-->')][0]
fd.close()

# isolate function name
funcname = current.split()[-1][1:-1]
return funcname

def XXX():
print whoami2()

XXX()
yy=XXX
a= yy()
zz=XXX
zz()

print "%s %s"%(yy(), zz())


# OUTPUT
XXX
yy
zz
yy
zz
None None

Sean Ross

unread,
May 20, 2003, 3:53:41 PM5/20/03
to
As a bonus, this even works for methods:

# I've changed the name of whoami2 to whoaminow
class c:
def foo(self):
print whoaminow()

inst = c()
inst.foo()
bar = inst.foo
bar()

#OUTPUTS
foo
bar

Terry Reedy

unread,
May 20, 2003, 6:39:11 PM5/20/03
to

"Sean Ross" <frobozz_...@hotmail.com> wrote in message
news:badusu$3fi$1...@driftwood.ccs.carleton.ca...

> Okay, here you go...This function will identify the called functions
name by
> it's proper name or by it's alias, however it's being called. It
grabs the
> frame where the function was called, gets the associated code object
and
> last instruction index, disassembles the code object, isolates the
> instruction, and slices out the function name. I don't know if this
is
> robust, dangerous, or whatever, but it does what you're asking for.

As I pointed out in my first response to the OP, functions do not
necessarily have a 'called-by' name.

# revised be removing blank lines so cut and paste works

def XXX():
print whoami2()

>>> XXX()
XXX # verifies copy ok
>>> fl=[XXX]
>>> fl[0]()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in XXX
File "<stdin>", line 18, in whoami2
IndexError: list index out of range

I suppose you could wrap that line in try:except: and return '' in
this case. But the user had better be prepared for a null name.

Terry J. Reedy


Sean Ross

unread,
May 20, 2003, 8:33:54 PM5/20/03
to
"Terry Reedy" <tjr...@udel.edu> wrote in message news:4U-

> >>> XXX()
> XXX # verifies copy ok
> >>> fl=[XXX]
> >>> fl[0]()
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> File "<stdin>", line 2, in XXX
> File "<stdin>", line 18, in whoami2
> IndexError: list index out of range
>
> I suppose you could wrap that line in try:except: and return '' in
> this case. But the user had better be prepared for a null name.
>


Oddly enough, I don't get that error, however I do not the name I'm looking
for either, so for the time being I've added an else clause to the for loop.
Now, if I don't find the name, I return None so the user can tell that the
name was not found by checking for this condition.

def whoaminow():


"returns name of called calling function"
import sys, dis
# get frame where calling function is called
frame = sys._getframe(2)
# get code and next to last instruction from frame
code = frame.f_code
lasti = frame.f_lasti-3
# redirect ouput of disassemble (stdout)
oldout = sys.stdout
sys.stdout = open('log','w')
dis.disassemble(code, lasti)
sys.stdout.close()

sys.stdout = oldout # restore stdout


# retrieve current byte code line
fd = open('log')

for line in fd.xreadlines():
if line.startswith('-->'):
break
else:
line = None


fd.close()
# isolate function name

if line:
funcname = line.split()[-1][1:-1]
else:
funcname = None
return funcname

# some testing...
def foo():
me = whoaminow()
return me

fl = [foo]
print fl[0]()

#outputs
None


Sean Ross

unread,
May 20, 2003, 9:15:55 PM5/20/03
to
Unfortunately, this code fails for any function with more than zero
arguments (which is most of them!). So... I tried...no luck...moving on...

Gerrit Holl

unread,
May 21, 2003, 5:34:27 AM5/21/03
to
Sean Ross schreef op dinsdag 20 mei om 21:29:01 +0000:

> # redirect ouput of disassemble (stdout)
> oldout = sys.stdout
> sys.stdout = open('log','w')
> dis.disassemble(code, lasti)
> sys.stdout.close()
>
> # restore stdout
> sys.stdout = oldout

I think backuping sys.stdout is not necessary, as sys.__stdout__
exists for that goal.

yours,
Gerrit.

--
117. If any one fail to meet a claim for debt, and sell himself, his
wife, his son, and daughter for money or give them away to forced labor:
they shall work for three years in the house of the man who bought them,
or the proprietor, and in the fourth year they shall be set free.

Sean Ross

unread,
May 21, 2003, 10:27:56 AM5/21/03
to
Okay, thanks. I've never needed to redirect stdout before, so I didn't know.
I also didn't know about the dis module before this little failed
experiment, so I've managed to get a few things out of this.

"Gerrit Holl" <ger...@nl.linux.org> wrote in message
news:mailman.1053509733...@python.org...

Steven Taschuk

unread,
May 21, 2003, 1:55:21 PM5/21/03
to
Quoth Gerrit Holl:
[...]

> I think backuping sys.stdout is not necessary, as sys.__stdout__
> exists for that goal.

But what if the caller of this code has itself changed sys.stdout
temporarily for some reason? Backup and restore is a good idea.

(Though obviously it would be best for this application if dis
weren't hard-coded to use sys.stdout.)

--
Steven Taschuk 7\ 7'Z {&~ .
stas...@telusplanet.net Y r --/hG-
(__/ )_ 1^1`

Erik Max Francis

unread,
May 21, 2003, 2:33:31 PM5/21/03
to
Gerrit Holl wrote:

> I think backuping sys.stdout is not necessary, as sys.__stdout__
> exists for that goal.

If this is intended to act as a standalone script, you of course have a
point. If it's a library function, though, sys.stdout may have already
been overridden at some point and you may want to be safe.

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
__ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
/ \ Have you ever loved somebody / Who didn't know
\__/ Zhane

0 new messages