Note: this is an extension of the question posed by Getting the name of a variable as a string and particularly the answer by @juan-Isaza:
import inspect
def variable_name(variable):
'''
Argument:
variable: the variable to search for from outer-most frame inner-wards
Returns:
name (str): the string characters corresponding to the name of the
variable
'''
for fi in reversed(inspect.stack()):
names = [
var_name
for var_name, var_val in fi.frame.f_locals.items()
if var_val is variable
]
if len(names) > 0:
return names[0]
The main issue is the line if var_val is variable
. Why? well atomic values such as True
, False
, None
all have the same id. So testing via is
results in the first boolean variable matching.
When / why might this come up?
Suppose you are over-engineering a way to wrap a configurable command to launch via subprocess
:
def line_arg(arg):
return '{} {}'.format(variable_name(arg), arg)
def short_arg(arg):
return '-{}'.format(line_arg(arg)).split(' ')
def long_arg(arg):
return '--{}'.format(line_arg(arg)).split(' ')
def flag_arg(flag, short=True):
dashes = '-' if short else '--'
return '{}{}'.format(dashes, variable_name(flag)) if flag else ''
then you might have:
def some_bash_command(
a_short_arg:str,
a_long_arg:str,
flag_1:bool=False
flag_2:bool=True
):
# ???
command = [
'some-bash-command',
'some-sub-arg',
*short_arg(a_short_arg),
*long_arg(a_long_arg),
flag_arg(flag1, short=True),
flag_arg(flag2, short=True)
]
return [part for part in command if part != '']
which you would then hope to have return (assuming flag1=False
)
[
'some-bash-command',
'some-sub-arg',
'-a_short_arg',
<a_short_arg_value>
'--a_long_arg',
<a_long_arg_value>
'-flag2'
]
# then call subprocess.Popen(args = command, ...)
However, instead of flag2
you will get the first boolean variable (for me stop_on_error
).
A solution would be to replace the line # ???
with:
import uuid
def some_bash_command(...):
if flag1: flag1 = uuid.uuid4() # <--- unique value
if flag2: flag2 = uuid.uuid4() # <--- unique value
...
which will circumvent this issue.
Unfortunately, that code can not exist in flag_arg
import uuid
def flag_arg(flag, short=True):
if flag: flag = uuid.uuid4() # <--- this is a no go
dashes = '-' if short else '--'
return '{}{}'.format(dashes, variable_name(flag)) if flag else ''
as then the variable_name
function will return flag
every time.
So the question is specifically how might one modify (if it is even possible) @juan-isaza's answer to handle atomic values like True
/ False
/ None
etc?
I understand that the example above is not the best example and in practice it may just be simpler to do list concatenation / string formatting than using the functions provided above. They are provides to be part of a MWE.