1

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.

SumNeuron
  • 4,850
  • 5
  • 39
  • 107

0 Answers0