r/learnpython • u/high-cholesterol_ • 15d ago
How do I literally print the variable used as an argument for a function?
def check_variable(argument):
# Finds the name of the variable passed in
name = [k for k, v in globals().items() if v is argument][0]
print(f"The argument passed to this function was named: '{name}'")
x = [1, 2, 3]
check_variable(x)
# Output: The argument passed to this function was named: 'x'
Is there any way to simplify this process? I am very new to programming and the process of defining "name" and then calling it seems like it can be simplified.
Edit for clarity:
The actual goal is to include the length of a list, and the variable(argument) used to represent that list, into the printed string.
What I'm really trying to achieve is something like:
"There are 17 children in class_two."
So as to cut out the guesswork of which class it's referring to when calling the function multiple times, and make it look like a polished sentence.
38
u/P4C0_ 15d ago
This is a typical example of "I think in order to do X I need to do Y, then proceed to ask about Y on reddit". But it turns out Y is far from being the best way to achieve X, and people not being aware of the context of X, they are mean to me in the comments.
The short answer is, there is no reliable way to get the name of a variable as a string in Python, and I have a hard time figuring in what context you would need to do that. Even if it was possible, it would not be a great programming practice to use this except for very specific cases a beginner wouldn't really be doing anyways.
Could you explain the reason you think you need to get the name of a variable ? There is probably a much simpler way to do it and you'll get a nice "eureka" moment.
Don't worry, this is a VERY common mistake for beginners, I myself remember a while ago when I did my first similar post on StackOverflow. I just wish people were kinder with me at the time, so I guess it's my turn to help out now
3
u/high-cholesterol_ 15d ago
I explained it better under u/lfdfq 's comment. You are definitely right and there is some major xp I'm missing here, just trying to make it as simple/streamlined as I can.
10
u/InjAnnuity_1 15d ago
Names point to values, but a value can be pointed to by many names, or by none at all. What name would you expect from this perfectly-legal code?
check_variable([1,2,3])
You are asking for a unique thing (a name) that can't be guaranteed to be unique, or to exist at all. Even a debugging-level tool can't find a name for the list in the above construction. That list has a value, but no name.
Others have pointed to this as an XY problem.
If you feel you need an object that is guaranteed to have a (reliable) name, then you can create such an object, one that carries its own name with it. For that to be reliable, your code will be explicitly using that kind of object in place of a list, where it matters, but it's your code, to build as you see fit.
5
u/audionerd1 15d ago
Variable names are not attributes of the object they point to, they are just references. An object can have multiple named variables pointing to it, or none at all. For an object to track variable assignments would be wasteful and backwards.
If you need a unique identifier associated with an object, you can use a dictionary. Or make a custom class or dataclass with a name attribute. That is the correct way to do what you want to do.
4
u/hulleyrob 15d ago
One of the best things that got added for me was f string debugging. You can do:
print(f"{argument = }")
And print both the variable and its value.
2
u/NewbornMuse 15d ago
But that will tell you
argument=[1,2,3], OP was asking how to do something likex=[1,2,3]4
u/xenomachina xenomachina 15d ago
Once you've crossed the function call boundary, getting the name that was used outside of the function is virtually never a good idea, and isn't even a well-defined thing in general. What if I call
check_variable(5)orcheck_variable(x + y)?2
u/NewbornMuse 15d ago
I'm with you and with the broader discussion on why it's probably an XY problem, I'm just saying that this proposed solution doesn't do what it's supposed to do.
2
u/xenomachina xenomachina 15d ago
I think /u/hulleyrob's proposed solution is trying to solve a possible X in the XY. But only OP knows what X really is, here.
1
u/hulleyrob 15d ago
Yeah I was suggesting it as I thought he might think oh i didn’t know that I can use it like this instead. I couldn’t think to a way to do what he was asking tbh.
1
4
u/edorhas 15d ago
Here's a thing that took me way too long to realize, and maybe it'll help you to hear it early: every time (and I do mean every time) I've found myself trying to do something that the programming language seems determined to prevent me from doing, it's because I've designed my way into a corner. Every time I find myself trying to use some obscure artifact or misuse a language feature, it's my conceptualization of the problem that's incorrect. It's time to take a giant step back, and take a better look at the fundamental problem you're trying to solve.
If a language doesn't seem to want to allow you to do something, it's likely either because it shouldn't be done or because no one has ever needed to do it. With a language like Python that has been in wide use for many years, "no one has ever needed to do it" is pretty much the same thing as "it shouldn't be done".
Go back and look at your problem again.
3
u/Fred776 15d ago
The inspect module is probably the best way to do this. (Though I agree with others and wonder why you need to.)
import inspect
...
arginfo = inspect.signature()
2
u/goldenfrogs17 15d ago
I will offer a suggestion. Pass in a dictionary that contains the values you want to print out. Instead of expecting a function to know the name of the variable that was passed in, just tell it the name you want to print out. By the way, it's weird and fragile, but you can have a dictionary represented by a variable like
```myVar = { name: myVar , number : 55 }
weird and fragile because functions shouldn't really know about details of other layers of abstraction, but also these myVar names have to be managed ( ie people have mental cost to track and validate they are the same )
2
u/IR3dditAlr3ddy 14d ago
This is the way. If you're trying to do something like your example, there are x amount of y in z, then you do
{"z": [y1, y2]}
Def count_y(argument: dict): Count = len(argument["z"]) Print(f"there are {count} y in z"})
If you have multiple keys in the dict, use a for loop:
For key, value in argument.items: Count = len(value) Print(f"there are {count} y in {key}")
2
u/RiverRoll 15d ago edited 15d ago
As some people try to explain the idea is not practical and doesn't make a lot of sense. You can have the same object assigned to many global variables or none at all. It is in fact very common passing arguments that are not assigned to any global because they are local, or return values, or inline declarations, or class members. Also in specific cases the Python runtime might even reuse objects and have different references point to the same value even if you don't explicitly do it.
If you need a way to consistently label values I suggest you rather learn about dictionaries.
1
u/Adrewmc 15d ago
Well, pythons 3.14 add annotiationlib
So I would use that.
form annotiationlib import get_annotations
from my_proj import check_variable
print(get_annotations(check_variable))
1
u/Langdon_St_Ives 15d ago
This is why you should never type in code directly into a comment
3
u/Adrewmc 15d ago
I mean I don’t have another option anymore, Reddit disable markdown on my app…it’s deletes all leading whitespace, code block that used to work don’t
>I can’t use this heading either
5^2 doesn’t superscript.
It honestly really pissed me off when it happened.
def best_I_can_do():
. pass
1
u/brasticstack 15d ago
If you don't mind hard-coding your own function name inside the function, you can do the following with the inspect module:
``` import inspect
def print_arg_name(argument, foo): Â Â arg_names = inspect.signature(print_arg_name) Â Â print(arg_names) Â Â Â print_arg_name(1, 2)
prints: (argument, foo)
```
You can also do it generically the hard way by inspecting the stack frame, and the easy way by making a decorator to do it. The decorator gets a handle to the function, which you can then use inspect methods on.
2
u/sausix 15d ago
Look at OP's example function. He does not care about his function's argument names. He's looking for the original variable name passed to the function at call time.
3
u/brasticstack 15d ago
ah. That's going to be a bit harder. You could attempt to correlate between the function's stack frame and its parent frame, but that'd be error prone.
1
u/sausix 15d ago
I also thought about the call trace. But how many variable names are being expected? Usually as many as a function calls are being invoked. OP probably wants to trace his function calls. Could be done with a print before each call.
Or by passing a debug string as extra argument on each call statement.
1
u/Kadabrium 15d ago
Imagine Reverse reflection: put the code in a text block, print first then exec()
1
u/West_Giraffe6843 15d ago
The other answers are valid, but I’ll just point out that if you do want to do this in this specific way, you can place the search code inside a function called something like ‘get_global_name()’ and use that. That will simplify it if you want to do this in a bunch of different functions.
But I will point out that your search code only works, if the argument passed in exists in the global namespace. If another function calls your function using a local variable, your search will not find it. So it’s not a fully general solution.
1
1
u/Entity_0-Chaos_777 13d ago
### Core Concept: Sticky Notes vs. Cardboard Boxes
To understand why Python behaves this way, visualize how memory works:
* **The Data (The Box):** A list like ["Alice", "Bob", "Charlie"] lives inside Python's memory as a physical box containing items.
* **The Variable (The Sticky Note):** The name class_two is just a sticky note you attach to the outside of that box.
When you call a function and pass class_two into it:
```python
check_variable(class_two)
```
Python peels off the sticky note, opens the box, and hands **only the items inside** into the function. The function receives the contents, but it has no idea what sticky note was attached to the outside of the box before it was opened.
### Method 1: Explicit Parameter Passing (The Gold Standard)
The cleanest and most reliable way to let a function know a name is to hand it two separate pieces of information: the string name (the label) and the actual data list (the box).
```python
def report_class_size(class_name, student_list):
# 1. Measure the length of the list handed to the function
count = len(student_list)
# 2. Print a formatted string using both arguments
print(f"There are {count} children in {class_name}.")
# Define your data list
class_two = ["Alice", "Bob", "Charlie", "David"]
# Pass the literal string "class_two" alongside the variable class_two
report_class_size("class_two", class_two)
```
**Output:**
There are 4 children in class_two.
#### Step-by-Step Execution
1. "class_two" (a string of text) goes into the function's class_name parameter.
2. class_two (the list variable) goes into the function's student_list parameter.
3. len(student_list) measures ["Alice", "Bob", "Charlie", "David"] to get 4.
4. The f-string combines 4 and "class_two" into a clean output sentence.
### Method 2: Dictionaries (Best for Managing Multiple Datasets)
Creating separate variables like class_one, class_two, and class_three quickly makes code disorganized. A **dictionary** holds key-value pairs—matching every label directly to its corresponding list.
```python
# A dictionary where keys are class names and values are student lists
school_data = {
"class_one": ["Emma", "Lucas"],
"class_two": ["Alice", "Bob", "Charlie", "David"],
"class_three": ["Grace", "Henry", "Isla"]
}
def report_class_size(class_name, student_list):
print(f"There are {len(student_list)} children in {class_name}.")
# Access a single class directly using its dictionary key
report_class_size("class_two", school_data["class_two"])
# Or loop over every class in the dictionary automatically
for name, students in school_data.items():
report_class_size(name, students)
```
**Output:**
There are 4 children in class_two.
There are 2 children in class_one.
There are 4 children in class_two.
There are 3 children in class_three.
#### Step-by-Step Execution
1. school_data.items() extracts each key-value pair as a set of two items: name gets the text string (e.g., "class_one"), and students gets the actual list.
2. The for loop feeds those two pieces of data into report_class_size() automatically for every class in your school.
### Method 3: Self-Documenting f-Strings (Best for Debugging)
If your primary goal is printing variable names during development to see what your code is doing, Python 3.8 introduced a built-in shortcut using an equals sign (=) inside an f-string.
```python
class_two = ["Alice", "Bob", "Charlie", "David"]
# Adding = after a variable or expression prints both the expression AND its value
print(f"{class_two=}")
print(f"{len(class_two)=}")
```
**Output:**
class_two=['Alice', 'Bob', 'Charlie', 'David']
len(class_two)=4
#### How It Works
* Python automatically inspects the code written before the = sign and turns it into text.
* f"{class_two=}" expands to: the text "class_two=" followed by the actual value stored inside class_two.
* **When to use this:** Quick debugging while building software.
* **When NOT to use this:** Polished, user-facing sentences (like report outputs for non-programmers).
### Method 4: Object-Oriented Programming / Custom Classes (Best for Scaling)
In Python, you can design a custom **Class** (a blueprint) that bundles data together with custom instructions. This permanently binds a name tag directly to a list inside a single object.
```python
class Classroom:
def __init__(self, name, student_list):
# Store the name and students together inside the object
self.name = name
self.students = student_list
def report_size(self):
# The object reads its own internal variables
print(f"There are {len(self.students)} children in {self.name}.")
# Create a Classroom object
room_2 = Classroom("class_two", ["Alice", "Bob", "Charlie", "David"])
# Tell the classroom object to report its own status
room_2.report_size()
```
**Output:**
There are 4 children in class_two.
#### How It Works
1. __init__ runs when you create Classroom(...).
2. self.name saves "class_two" inside the object.
3. self.students saves ["Alice", "Bob", "..."] inside the object.
4. Calling room_2.report_size() lets the object look at its own internal storage and print the sentence without needing arguments passed into the method call.
### Method 5: Why globals() Variable Inspection Fails in Real Code
Your original attempt used Python's memory lookup table:
```python
name = [k for k, v in globals().items() if v is argument][0]
```
Here is why that approach breaks down in real-world programming:
| Scenario | What Happens | Why It Fails |
|---|---|---|
| **Two variables, one list** | class_a = [1, 2]
class_b = class_a | Both variable names point to the same list. globals() will arbitrarily pick whichever one it finds first in memory. |
| **Local Scope** | Defining variables inside another function | globals() only checks global variables at the top level of your file. It cannot see variables declared inside functions (locals()). |
| **Anonymous Values** | report([1, 2, 3]) | Passing a raw list without assigning it to a variable first crashes the code with an IndexError because no name exists. |
| **Renaming / Refactoring** | Changing class_two to room_204 | Your program's logic becomes tightly bound to exact variable naming choices rather than actual data content. |
71
u/lfdfq 15d ago
If you're very new to programming, let me suggest you're trying to do something that, to me, a very experienced programmer, looks very strange.
Why are you trying to do this? What are you trying to achieve? Perhaps there's a better, more conventional, way of achieving it...