-1

I am a programmer new to python trying to write a simple test1() function that uses arg (or *arg) to print out how it was called using the "name" of the argument passed to it, not the content of the list or any other variable that I am passing.

The following example:

def test1(arg):

    print "name of arg is %r" % arg


alphabet = ['a', 'b', 'c']

test1(alphabet) # prints name of arg is ['a', 'b', 'c']

I want it to print out: name of arg is alphabet I researched and tried several things related to using *argv but did not succeed. Can someone shed some light on this? I feel like I'm missing something obvious. Thanks!

georg
  • 211,518
  • 52
  • 313
  • 390
Tom D
  • 1
  • 3
  • 4
    Python objects are [like stray cats](https://docs.python.org/3/faq/programming.html#how-can-my-code-discover-the-name-of-an-object): they don't know or care about their names, and may have multiple names or be nameless. – Kevin Mar 10 '15 at 19:23
  • This is nowhere near a duplicate. In fact it has nothing to do with *argv* as it's known in programming world – Tim Mar 10 '15 at 19:23
  • @TimCastelijns Oops, you're right. I should have read the question more carefully. I removed my duplicate comment. Unfortunately, I cannot remove my flag, but I think the discerning moderator will dismiss my flag. I apologize, Tom D. – dbank Mar 10 '15 at 19:30
  • I don't think this duplicates that. The OP hasn't so much as mentioned command line arguments. Voting to reopen. – Adam Smith Mar 10 '15 at 19:37
  • Sorry, the closing is my fault (at least partly). Can we please get a moderator to reopen? – dbank Mar 10 '15 at 19:39

2 Answers2

1

This is more than a little ugly, but it's one way to achieve what you're after:

import traceback
import re

alphabet = ['a', 'b', 'c']

def test(arg):
    stack = traceback.extract_stack()
    arg_name = re.sub('test\((.*)\)', '\g<1>', stack[-2][-1])
    print arg_name

test(alphabet)
test('foo')

The result of which is

alphabet
'foo'
Demian Brecht
  • 21,135
  • 5
  • 42
  • 46
  • 2
    If I ever saw this in production code, I would weep silently. +1 – Adam Smith Mar 10 '15 at 19:50
  • 1
    @AdamSmith: I would weep, but it most definitely would *not* be silently ;) – Demian Brecht Mar 10 '15 at 19:51
  • @Demian - It's beautiful to me, regular expressions and all ! I have a lot to learn. Cheers! – Tom D Mar 10 '15 at 20:44
  • 1
    @TomD If you learn one thing about programming, make it be to NEVER DO SOMETHING LIKE THIS. Make code that's self-documenting and easy to read. Regular expressions are great and well worth your time to look up, but using them to manually hack apart a stack trace is the definition of ugly, hacky code. – Adam Smith Mar 11 '15 at 20:57
  • @AdamSmith - appreciate the sage advice. Even though I am a Python noob, I am a former C/Unix systems programmer who used re's in scripts and editors . For that reason, I really enjoyed Demian's solution. Still, I can't help but wonder if a solution like his should be part of a system library, or would it somehow be non-conforming to Python's methodology regarding names and references? – Tom D Mar 13 '15 at 20:00
  • 1
    Kevin's comment in response to your question is Python's stance on the matter. Keep data out of identifiers, and you'll never need to know what the identifier is. – Adam Smith Mar 13 '15 at 23:39
0

I'm not quite sure, why you want this, anyway ...

If you want the name of argument available in a function, you have to pass the name of the argument to the function. Python is call by reference in all cases.

In your function, arg will always be named arg inside the function. Its outside variable name is not available inside the function.

def test1(arg):
    print "name of arg is %r" % arg

However python has variable keyword arguments and there lies a possible solution to your problem. Let me redefine test1():

def test1(**kwargs):
   param_name = iter(kwargs).next()
   print "name of parameter is %s" % param_name

You can call this function with a keyword argument:

alphabet = ['a', 'b', 'c']
test1(alphabet=alphabet)

Note, however, that what get's printed is not the variable name from outside the function, but the name of the keyword.

georg
  • 211,518
  • 52
  • 313
  • 390
dhke
  • 15,008
  • 2
  • 39
  • 56
  • dhke, Thanks for the quick help! The reason I wanted the test1() function was to be able to call it from various places in a large program. Knowing the name or names of the argument(s) passed would help in determining where it was called from. It was going to be a useful log or learning tool. I realize there are other ways to achieve the same results. Your **kwargs solution will work as well as passing a second argument with a string that tells the name of the arg being passed. Being new to Python, I just thought there might be something else more efficient that I was missing. Thanks again! – Tom D Mar 10 '15 at 19:31
  • python actually passes object references by value. if it were truly pass by reference, this would work: `j = 61; def f(i): i = 7; f(j); assert(j == 7)` – acushner Mar 10 '15 at 19:33
  • @acushner If you want to be that correct, you get pass by reference, but you get a *copy of the reference*, same as e.g. Java does it. C++ of course is a little different. – dhke Mar 10 '15 at 19:52
  • yeah, it passes the reference by value. – acushner Mar 10 '15 at 19:53
  • @TomD Well. You can always get a the stack frame and find out the hard way, where you are being called from. But that's not terribly efficient. – dhke Mar 10 '15 at 19:53
  • 1
    @acushner - succinctly stated and I now completely understand. Thank you. – Tom D Mar 10 '15 at 20:04
  • @dhke - I thought I was trying the stack frame route in some of my attempts by using sys.argv but it did not get me to the right place. With less than a month of python under my belt, I should probably be focused on simpler tasks to debug, reverse engineer and learn the language. Nevertheless, I learned a lot here. Thanks to all of you! I'll be back. – Tom D Mar 10 '15 at 20:20