getting name of passed reference

J

Joel Davis

I'm just curious if anyone knows of a way to get the variable name of
a reference passed to the function.

Put another way, in the example:

def MyFunc ( varPassed ):
print varPassed;

MyFunc(nwVar)

how would I get the string "nwVar" from inside of "MyFunc"? is it
possible?
 
E

Emile van Sebille

On 12/28/2009 3:54 PM Joel Davis said...
I'm just curious if anyone knows of a way to get the variable name of
a reference passed to the function.

For curiosity, sure -- but it's real weak...
Put another way, in the example:

def MyFunc ( varPassed ):
print varPassed;

MyFunc(nwVar)

how would I get the string "nwVar" from inside of "MyFunc"?

Here are some ways of doing this:
http://www.python-forum.org/pythonforum/viewtopic.php?f=14&t=12659
is it possible?

Yes -- but only for a limited set of situations. Consider the following:

MyFunc(3)

a=[1,2,3,4]
MyFunc(a[2])

b=a
MyFunc(b[2])

def newval(): return 3
MyFunc(newval())

MyFunc(range(3)[-1])

Emile
 
J

Joel Davis

For posterity, I figured out a solution:
> #!/usr/bin/python
> import sys
> from traceback import extract_stack
> varPassed="varName get"
> def MyFunc(varPassed):
> try:
> raise None
> except:
> frame = sys._getframe(1)
> print extract_stack(frame,2)[0][3]

> MyFunc(varPassed)


the print statement returns the full function call including
parameters as they were written in the script (variable names and all)


On 12/28/2009 3:54 PM Joel Davis said...
I'm just curious if anyone knows of a way to get the variable name of
a reference passed to the function.

For curiosity, sure -- but it's real weak...
Put another way, in the example:
   def MyFunc ( varPassed ):
      print varPassed;
   MyFunc(nwVar)
how would I get the string "nwVar" from inside of "MyFunc"?

Here are some ways of doing this:http://www.python-forum.org/pythonforum/viewtopic.php?f=14&t=12659
is it possible?

Yes -- but only for a limited set of situations.  Consider the following:

MyFunc(3)

a=[1,2,3,4]
MyFunc(a[2])

b=a
MyFunc(b[2])

def newval(): return 3
MyFunc(newval())

MyFunc(range(3)[-1])

Emile

at first glance the solution i came up with seems to be in general the
same as the one presented there, are there any portability issues
you're aware of? also, when can one _not_ get the name?
 
S

Steven D'Aprano

I'm just curious if anyone knows of a way to get the variable name of a
reference passed to the function.

Put another way, in the example:

def MyFunc ( varPassed ):
print varPassed;

MyFunc(nwVar)

how would I get the string "nwVar" from inside of "MyFunc"? is it
possible?

Not via standard Python. There are a few ways of guessing a possible name
using frames, but:

(1) all such solutions are nasty hacks;
(2) some of them require the source code to be available, which isn't
always the case;
(3) they almost certainly won't be portable to other Python
implementations;
(4) they're probably expensive and relatively slow; and
(5) not all objects have a name, and some objects have multiple names.


For example, here's one way to get a list of all the names that an object
is known as (if any):


def get_names(obj, level=1):
# WARNING: this uses implementation-specific Python private details
frame = sys._getframe(level)
return [k for (k, v) in frame.f_locals.items() if v is obj]


And here's an example of it in use:
var = 'foo'
c = 'foo'
get_names('foo') ['c', 'var']
get_names(25) []
def test(x):
.... print get_names(x, 2)
....['c', 'var']



Notice that, in general, there's NO WAY to tell from inside test that the
string was passed using the name 'var' rather than the name 'c'.



Why do you want to do such a thing?
 
S

Steven D'Aprano

For posterity, I figured out a solution:
#!/usr/bin/python
import sys
from traceback import extract_stack
varPassed="varName get"
def MyFunc(varPassed):
try:
raise None
except:
frame = sys._getframe(1)
print extract_stack(frame,2)[0][3]

MyFunc(varPassed)


Incorrect. Here's a copy-and-paste from an interactive session using that
code:

.... try:
.... raise None
.... except:
.... frame = sys._getframe(1)
.... print extract_stack(frame,2)[0][3]
....
the print statement returns the full function call including parameters
as they were written in the script (variable names and all)

I'm afraid not. I don't know what testing you did, but it doesn't work as
you think it works.

Also, I notice that you've called the variable local to the function the
same name as the variable in the outer scope. What happens when you do
this?
None


at first glance the solution i came up with seems to be in general the
same as the one presented there, are there any portability issues
you're aware of?

Yes.


sys._getframe is a PRIVATE function, which means it is subject to change
without notice. You're using an internal function clearly marked as
private. It is unlikely to even exist at all in other implementations of
Python (e.g. Jython, IronPython, PyPy, CLPython, etc.), and it might not
even exist in future versions of CPython.


also, when can one _not_ get the name?

When the object doesn't have a name at all, or when it has multiple
names. Which is "the" name?
 
J

Joel Davis

For posterity, I figured out a solution:
 > #!/usr/bin/python
 > import sys
 > from traceback import extract_stack
 > varPassed="varName get"
 > def MyFunc(varPassed):
 >         try:
 >                 raise None
 >         except:
 >                 frame = sys._getframe(1)
 >                 print extract_stack(frame,2)[0][3]
 > MyFunc(varPassed)

Incorrect. Here's a copy-and-paste from an interactive session using that
code:

...     try:
...         raise None
...     except:
...         frame = sys._getframe(1)
...         print extract_stack(frame,2)[0][3]
...
None

the print statement returns the full function call including parameters
as they were written in the script (variable names and all)

I'm afraid not. I don't know what testing you did, but it doesn't work as
you think it works.

Also, I notice that you've called the variable local to the function the
same name as the variable in the outer scope. What happens when you do
this?
None

at first glance the solution i came up with seems to be in general the
same as the one presented there,  are there any portability issues
you're aware of?

Yes.

sys._getframe is a PRIVATE function, which means it is subject to change
without notice. You're using an internal function clearly marked as
private. It is unlikely to even exist at all in other implementations of
Python (e.g. Jython, IronPython, PyPy, CLPython, etc.), and it might not
even exist in future versions of CPython.
also, when can one _not_ get the name?

When the object doesn't have a name at all, or when it has multiple
names. Which is "the" name?

steven, when I said that's what the code returned I was explaining
what I saw when I ran it, if you're having trouble running it in the
interactive terminal, then that's probably because it can't be ran in
the interactive terminal.
 
J

Joel Davis

As far as more positive things are concerned, is anyone aware of what
the support for _getframe(1) the way I used it is? Does steven have a
newer (or older) version than me, maybe? (2.6.2) it seems like the
sort of thing that ought to have pretty uniform behavior, but are
their certain calls it varies on?
 
J

Joel Davis

As far as more positive things are concerned, is anyone aware of what
the support for _getframe(1) the way I used it is? Does steven have a
newer (or older) version than me, maybe? (2.6.2) it seems like the
sort of thing that ought to have pretty uniform behavior, but are
their certain calls it varies on?

my thanks go out to Emile and Mr Hanson for their responses, I think
I've found the solution, much shorter as well:
> #!/usr/bin/python
> import traceback
> def testing ( varPassed ):
> print traceback.extract_stack()[0][3]
> testing("123")

and it seems the traceback module in general seems to have a lot of
history to it. This project is for CPython so compatibility with
Jython, Iron Python, et al isn't really that important right now. So
as far as functionality and compatibility I think I'm set as long as
traceback.extract_stack is 3.0 safe.
 
S

Steven D'Aprano

my thanks go out to Emile and Mr Hanson for their responses, I think
I've found the solution, much shorter as well:
#!/usr/bin/python
import traceback
def testing ( varPassed ):
print traceback.extract_stack()[0][3]
testing("123")

and it seems the traceback module in general seems to have a lot of
history to it. This project is for CPython so compatibility with Jython,
Iron Python, et al isn't really that important right now. So as far as
functionality and compatibility I think I'm set as long as
traceback.extract_stack is 3.0 safe.


I'm afraid that one fails again. Do you actually test your solutions
before telling us you've solved the problem?

.... print traceback.extract_stack()[0][3]
....None

When a "solution" doesn't work under some circumstances (in this case,
when run in the interactive interpreter) that's a warning that you need
to understand when and where it will work before using it in production.
Otherwise, how do you know that it will work under other circumstances?

Or, find an alternative. What are you actually trying to do? "Get the
name of a passed reference" is a means to an end. What are you expecting
to do with it?
 
G

Gabriel Genellina

On Dec 28, 9:37 pm, Joel Davis <[email protected]> wrote:
my thanks go out to Emile and Mr Hanson for their responses, I think
I've found the solution, much shorter as well:
#!/usr/bin/python
import traceback
def testing ( varPassed ):
print traceback.extract_stack()[0][3]
testing("123")

and it seems the traceback module in general seems to have a lot of
history to it. This project is for CPython so compatibility with
Jython, Iron Python, et al isn't really that important right now. So
as far as functionality and compatibility I think I'm set as long as
traceback.extract_stack is 3.0 safe.

Test with this:

def f(): return g()
def g(): return h()
def h(): testing("123")
f()

You probably want traceback.extract_stack()[-2][3] instead.

Note that your solution solves a different problem: you asked "the name of
the passed object" and testing() above prints "the source line of the
previous stack frame". This method may be good enough for you, but you
should be aware of its limitations:

- The source code (.py file) of the module containing the calling function
must be present (a .pyc file is not enough).
- It must be a plain text file in the filesystem, directly reachable in a
directory along sys.path (it may not be contained in a .zip file, an .egg,
or use any other kind of import mechanism).
- The source retrieval may fail if your program changes the current
directory
- If the calling function is not actually inside a module, you can't
retrieve its source (e.g. when using exec/eval, or from inside the
interactive interpreter).
- Only the last line of the function invocation is returned; you miss all
its previous lines and/or arguments.

I'm sure other limitations apply too -- don't rely on this technique for
anything critical.
 
J

Joel Davis

my thanks go out to Emile and Mr Hanson for their responses, I think
I've found the solution, much shorter as well:
    > #!/usr/bin/python
    > import traceback
    > def testing ( varPassed ):
    >         print traceback.extract_stack()[0][3]
    > testing("123")
and it seems the traceback module in general seems to have a lot of
history to it. This project is for CPython so compatibility with Jython,
Iron Python, et al isn't really that important right now. So as far as
functionality and compatibility I think I'm set as long as
traceback.extract_stack is 3.0 safe.

I'm afraid that one fails again. Do you actually test your solutions
before telling us you've solved the problem?

...     print traceback.extract_stack()[0][3]
...

None

When a "solution" doesn't work under some circumstances (in this case,
when run in the interactive interpreter) that's a warning that you need
to understand when and where it will work before using it in production.
Otherwise, how do you know that it will work under other circumstances?

Or, find an alternative. What are you actually trying to do? "Get the
name of a passed reference" is a means to an end. What are you expecting
to do with it?

Steven I don't know what your issue is, but it works for me. If your
having trouble running the code, then that's your issue, and I would
appreciate it if you would just shut up until you know what the hell
you're talking about. I say that because if you paid the slightest
attention my first solution that you found so woefully inept IS
BASICALLY YOUR FIRST SOLUTION RECONFIGURED.

You also apparently can't read.
 
J

Joel Davis

En Tue, 29 Dec 2009 00:28:32 -0300, Joel Davis <[email protected]>  
escribió:


my thanks go out to Emile and Mr Hanson for their responses, I think
I've found the solution, much shorter as well:
    > #!/usr/bin/python
    > import traceback
    > def testing ( varPassed ):
    >         print traceback.extract_stack()[0][3]
    > testing("123")
and it seems the traceback module in general seems to have a lot of
history to it. This project is for CPython so compatibility with
Jython, Iron Python, et al isn't really that important right now. So
as far as functionality and compatibility I think I'm set as long as
traceback.extract_stack is 3.0 safe.

Test with this:

def f(): return g()
def g(): return h()
def h(): testing("123")
f()

You probably want traceback.extract_stack()[-2][3] instead.

Note that your solution solves a different problem: you asked "the name of  
the passed object" and testing() above prints "the source line of the  
previous stack frame". This method may be good enough for you, but you  
should be aware of its limitations:

- The source code (.py file) of the module containing the calling function  
must be present (a .pyc file is not enough).
- It must be a plain text file in the filesystem, directly reachable in a  
directory along sys.path (it may not be contained in a .zip file, an .egg,  
or use any other kind of import mechanism).
- The source retrieval may fail if your program changes the current  
directory
- If the calling function is not actually inside a module, you can't  
retrieve its source (e.g. when using exec/eval, or from inside the  
interactive interpreter).
- Only the last line of the function invocation is returned; you miss all  
its previous lines and/or arguments.

I'm sure other limitations apply too -- don't rely on this technique for  
anything critical.

Gabriel,

thanks for your input, I had no idea that did that and it could have
been deployed without even being aware of it, caused consternation and
headaches galore.
 
S

Steve Holden

Joel said:
my thanks go out to Emile and Mr Hanson for their responses, I think
I've found the solution, much shorter as well:
#!/usr/bin/python
import traceback
def testing ( varPassed ):
print traceback.extract_stack()[0][3]
testing("123")
and it seems the traceback module in general seems to have a lot of
history to it. This project is for CPython so compatibility with Jython,
Iron Python, et al isn't really that important right now. So as far as
functionality and compatibility I think I'm set as long as
traceback.extract_stack is 3.0 safe.
I'm afraid that one fails again. Do you actually test your solutions
before telling us you've solved the problem?
import traceback
def testing ( varPassed ):
... print traceback.extract_stack()[0][3]
...
testing("123") None
x = "123"
testing(x)
None

When a "solution" doesn't work under some circumstances (in this case,
when run in the interactive interpreter) that's a warning that you need
to understand when and where it will work before using it in production.
Otherwise, how do you know that it will work under other circumstances?

Or, find an alternative. What are you actually trying to do? "Get the
name of a passed reference" is a means to an end. What are you expecting
to do with it?

Steven I don't know what your issue is, but it works for me. If your
having trouble running the code, then that's your issue, and I would
appreciate it if you would just shut up until you know what the hell
you're talking about. I say that because if you paid the slightest
attention my first solution that you found so woefully inept IS
BASICALLY YOUR FIRST SOLUTION RECONFIGURED.

You also apparently can't read.

Whereas you appear to have a problem maintaining good manners.

regards
Steve
 
F

Francesco Bochicchio

I'm just curious if anyone knows of a way to get the variable name of
a reference passed to the function.

Put another way, in the example:

  def MyFunc ( varPassed ):
     print varPassed;

  MyFunc(nwVar)

how would I get the string "nwVar" from inside of "MyFunc"? is it
possible?


The following code shows one way to get both function name and
argument names from inside a function using module inspect in python
2.6:

import inspect

def myfunc(arg1, arg2):
f = inspect.currentframe()
funcname = inspect.getframeinfo(f).function
numargs = f.f_code.co_argcount
argnames = f.f_code.co_varnames[:numargs]
print funcname, argnames

myfunc(1, "ppp")

NOTE: it does not list parameters passed as list (*args) or as dict
(**kwd).

P.S . I use this to generate automatically trace messages of type
"called myfunc( arg1=1, arg2=ppp" ).
But I currently lack a way, from inside a method, to determine the
name of the class to which the
method belong, so I could automatically generate trace messages of
type "class.method called etc ...".
Pointers are welcome.

Ciao
 
J

Joel Davis

Joel said:
On Mon, 28 Dec 2009 19:28:32 -0800, Joel Davis wrote:
my thanks go out to Emile and Mr Hanson for their responses, I think
I've found the solution, much shorter as well:
    > #!/usr/bin/python
    > import traceback
    > def testing ( varPassed ):
    >         print traceback.extract_stack()[0][3]
    > testing("123")
and it seems the traceback module in general seems to have a lot of
history to it. This project is for CPython so compatibility with Jython,
Iron Python, et al isn't really that important right now. So as far as
functionality and compatibility I think I'm set as long as
traceback.extract_stack is 3.0 safe.
I'm afraid that one fails again. Do you actually test your solutions
before telling us you've solved the problem?
import traceback
def testing ( varPassed ):
...     print traceback.extract_stack()[0][3]
...
testing("123")
None
x = "123"
testing(x)
None
When a "solution" doesn't work under some circumstances (in this case,
when run in the interactive interpreter) that's a warning that you need
to understand when and where it will work before using it in production.
Otherwise, how do you know that it will work under other circumstances?
Or, find an alternative. What are you actually trying to do? "Get the
name of a passed reference" is a means to an end. What are you expecting
to do with it?
Steven I don't know what your issue is, but it works for me. If your
having trouble running the code, then that's your issue, and I would
appreciate it if you would just shut up until you know what the hell
you're talking about. I say that because if you paid the slightest
attention my first solution that you found so woefully inept IS
BASICALLY YOUR FIRST SOLUTION RECONFIGURED.
You also apparently can't read.

Whereas you appear to have a problem maintaining good manners.

regards
 Steve
--
Steve Holden           +1 571 484 6266   +1 800 494 3119
PyCon is coming! Atlanta, Feb 2010  http://us.pycon.org/
Holden Web LLC                http://www.holdenweb.com/
UPCOMING EVENTS:        http://holdenweb.eventbrite.com/

well not to engage in a he/she said, but in my own defense D'Aprano
did set the tone and I think I've been more than a little tolerant on
this. Someone posts a question, responds back with a "n/m I found the
solution, here it is" and his response is essentially to berate them,
telling them how crappy their code is and that they should at least
_try_ the code. Bear in mind that I even told him the reason he wasn't
able to run it is because he's pasting it into the interactive
terminal. He then responded back AGAIN with the same insults and the
same issue that shows he didn't really even read my last response.

If anything, I should be faulted for actually engaging him and not
just letting it go.
 
E

Emile van Sebille

On 12/29/2009 7:02 AM Joel Davis said...
Gabriel,

thanks for your input, I had no idea that did that and it could have
been deployed without even being aware of it, caused consternation and
headaches galore.

In an extremely controlled situation you may avoid headaches when
deploying this kind of technique. Regardless, we all want to make you
aware that this _will_ likely cause headaches, and, idle curiosity
aside, none of us can imagine the problem to which this is the
appropriate solution.

It's fun to work out, but you're probably better served if you describe
the problem you're solving and consider the alternatives suggested.

Dependence on introspection belongs in programming tools, not in
applications deployed across versions and platforms.

Emile
 
J

Joel Davis

On 12/29/2009 7:02 AM Joel Davis said...


In an extremely controlled situation you may avoid headaches when
deploying this kind of technique.  Regardless, we all want to make you
aware that this _will_ likely cause headaches, and, idle curiosity
aside, none of us can imagine the problem to which this is the
appropriate solution.

It's fun to work out, but you're probably better served if you describe
the problem you're solving and consider the alternatives suggested.

Dependence on introspection belongs in programming tools, not in
applications deployed across versions and platforms.

Emile

Emile, essentially, the situation is that I'm trying to create an API
for consumption scripting. As it stands now, in initial development
they can pass callback function. The idea was to enable them to pass
variables and have the handling function determine the type and just
drop the value into it instead of calling function with the value as
an argument. The problem with that approach is determining exactly
which variable was passed. My idea was to use this to capture the name
and then modify the globals for the executing frame so that the passed
variable represents the new value.
 
M

MRAB

Joel said:
Emile, essentially, the situation is that I'm trying to create an API
for consumption scripting. As it stands now, in initial development
they can pass callback function. The idea was to enable them to pass
variables and have the handling function determine the type and just
drop the value into it instead of calling function with the value as
an argument. The problem with that approach is determining exactly
which variable was passed. My idea was to use this to capture the name
and then modify the globals for the executing frame so that the passed
variable represents the new value.

All I can say is: Yuck! Don't do that! :)
 
M

Martin P. Hellwig

Joel said:
I'm just curious if anyone knows of a way to get the variable name of
a reference passed to the function.

Put another way, in the example:

def MyFunc ( varPassed ):
print varPassed;

MyFunc(nwVar)

how would I get the string "nwVar" from inside of "MyFunc"? is it
possible?

Would it be acceptable to require keyword arguments when calling the
function?
 
D

Dave Angel

Joel said:
Emile, essentially, the situation is that I'm trying to create an API
for consumption scripting. As it stands now, in initial development
they can pass callback function. The idea was to enable them to pass
variables and have the handling function determine the type and just
drop the value into it instead of calling function with the value as
an argument. The problem with that approach is determining exactly
which variable was passed. My idea was to use this to capture the name
and then modify the globals for the executing frame so that the passed
variable represents the new value.
I've never heard of "consumption scripting." Can you describe it in
simple terms?

I take it you're publishing a library of code that somebody can call to
do things. Can you characterize your users? Are they programmers, are
they Python programmers, are they scientists?

Presumably you're trying to define a language (not Python) that these
users can program in, where you want to achieve call by reference. I'm
sure you have some good reason for that, but could we hear it?

When you need to do something like this for programmers, the approach
might be for them to pass a collection object, and an identifier to
specify what part of the collection for you to modify. If the
collection object is their module, then the identifier could be just the
name of the identifier they want you to modify. In this case, the code
could be robust and readable.

Even better would be for them to pass you an object, and you can call
methods on that object to modify it in place. Just provide them a class
to create such an instance, and they can have as many of them as they like.

DaveA
 

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,779
Messages
2,569,606
Members
45,239
Latest member
Alex Young

Latest Threads

Top