programing tip

변수 이름을 문자열로 가져 오기

itbloger 2020. 8. 9. 10:10
반응형

변수 이름을 문자열로 가져 오기


이 스레드는 Python 에서 함수 이름을 문자열로 가져 오는 방법에 대해 설명합니다. Python 에서 함수 이름을 문자열로 가져 오는 방법은 무엇입니까?

변수에 대해 어떻게 똑같이 할 수 있습니까? 함수와 달리 Python 변수에는 __name__속성 이 없습니다 .

즉, 다음과 같은 변수가있는 경우 :

foo = dict()
foo['bar'] = 2

함수 / 속성을 찾고 있습니다. 예 retrieve_name:

retrieve_name(foo) 

그 문자열을 반환 'foo'

최신 정보:

사람들이 내가 왜 이것을하고 싶은지 묻기 때문에 여기에 예가 있습니다. 이 목록에서 Pandas에 DataFrame만들고 싶습니다 . 여기서 열 이름 은 실제 사전의 이름으로 지정됩니다.

# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]

표준 이름을 가진 Python의 유일한 객체는 모듈, 함수 및 클래스이며, 물론이 표준 이름이 함수 또는 클래스가 정의되거나 모듈을 가져온 후 모든 네임 스페이스에서 의미가 있다는 보장은 없습니다. 이러한 이름은 개체를 만든 후에도 수정할 수 있으므로 항상 특히 신뢰할 수있는 것은 아닙니다.

당신이 원하는 것은 명명 된 객체의 트리를 재귀 적으로 걷지 않고서 는 불가능하다 . 이름은 객체에 대한 단방향 참조입니다. 일반적인 또는 정원에 다양한 Python 객체에는 이름에 대한 참조가 없습니다. 모든 정수, 모든 딕셔너리, 모든 목록, 모든 부울이 자신을 참조하는 이름을 나타내는 문자열 목록을 유지해야한다고 상상해보십시오! 프로그래머에게는 거의 도움이되지 않는 구현 악몽이 될 것입니다.


변수 값이 이름을 다시 가리 키지 않더라도 할당 된 모든 변수와 해당 값의 목록에 액세스 할 수 있으므로 한 사람 만이 변수 이름을 찾기 위해 거기를 반복하는 것을 제안한 것이 놀랍습니다.

누군가가 그 대답에 대해 스택을 걸어보고 모든 사람의 지역 및 전역을 확인해야 할 수도 있다고 언급 foo했지만 fooretrieve_name함수를 호출하는 범위에 할당 된 경우 inspect's current frame사용 하여 모든 지역 변수를 얻을 수 있습니다. .

내 설명이 너무 말이 많을 수 있지만 ( "foo"를 적게 사용 했어야 함) 다음은 코드에서 어떻게 보이는지입니다 ( 동일한 값에 할당 된 변수가 두 개 이상인 경우 두 변수 이름을 모두 가져옵니다 ) :

import inspect

x,y,z = 1,2,3

def retrieve_name(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    return [var_name for var_name, var_val in callers_local_vars if var_val is var]

print retrieve_name(y)

다른 함수에서이 함수를 호출하는 경우 다음과 같습니다.

def foo(bar):
    return retrieve_name(bar)

foo(baz)

baz대신 을 원하면 bar범위를 더 뒤로 이동하면됩니다. 이것은 여분을 추가하여 수행 할 수 있습니다 .f_backcaller_local_vars초기화.

여기에서 예를보십시오 : ideone


나는 이것이 가능하다고 믿지 않는다. 다음 예를 고려하십시오.

>>> a = []
>>> b = a
>>> id(a)
140031712435664
>>> id(b)
140031712435664

ab같은 객체를 가리키고 있지만, 객체가 가리키는 파일 변수를 알 수 없다.


python3에서이 함수는 스택에서 가장 바깥 쪽 이름을 가져옵니다.

import inspect


def retrieve_name(var):
        """
        Gets the name of var. Does it from the out most frame inner-wards.
        :param var: variable to get name from.
        :return: string
        """
        for fi in reversed(inspect.stack()):
            names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
            if len(names) > 0:
                return names[0]

코드 어디에서나 유용합니다. 첫 번째 일치 항목을 찾기 위해 반전 된 스택을 탐색합니다.


def name(**variables):
    return [x for x in variables]

다음과 같이 사용됩니다.

name(variable=variable)

여기에 한 가지 접근 방식이 있습니다. 매우 부서지기 쉽기 때문에 중요한 것은 이것을 권장하지 않습니다. 하지만 할 수 있습니다.

Create a function that uses the inspect module to find the source code that called it. Then you can parse the source code to identify the variable names that you want to retrieve. For example, here's a function called autodict that takes a list of variables and returns a dictionary mapping variable names to their values. E.g.:

x = 'foo'
y = 'bar'
d = autodict(x, y)
print d

Would give:

{'x': 'foo', 'y': 'bar'}

Inspecting the source code itself is better than searching through the locals() or globals() because the latter approach doesn't tell you which of the variables are the ones you want.

At any rate, here's the code:

def autodict(*args):
    get_rid_of = ['autodict(', ',', ')', '\n']
    calling_code = inspect.getouterframes(inspect.currentframe())[1][4][0]
    calling_code = calling_code[calling_code.index('autodict'):]
    for garbage in get_rid_of:
        calling_code = calling_code.replace(garbage, '')
    var_names, var_values = calling_code.split(), args
    dyn_dict = {var_name: var_value for var_name, var_value in
                zip(var_names, var_values)}
    return dyn_dict

The action happens in the line with inspect.getouterframes, which returns the string within the code that called autodict.

The obvious downside to this sort of magic is that it makes assumptions about how the source code is structured. And of course, it won't work at all if it's run inside the interpreter.


I wrote the package sorcery to do this kind of magic robustly. You can write:

from sorcery import dict_of

columns = dict_of(n_jobs, users, queues, priorities)

and pass that to the dataframe constructor. It's equivalent to:

columns = dict(n_jobs=n_jobs, users=users, queues=queues, priorities=priorities)

>>> locals()['foo']
{}
>>> globals()['foo']
{}

If you wanted to write your own function, it could be done such that you could check for a variable defined in locals then check globals. If nothing is found you could compare on id() to see if the variable points to the same location in memory.

If your variable is in a class, you could use className.dict.keys() or vars(self) to see if your variable has been defined.


In Python, the def and class keywords will bind a specific name to the object they define (function or class). Similarly, modules are given a name by virtue of being called something specific in the filesystem. In all three cases, there's an obvious way to assign a "canonical" name to the object in question.

However, for other kinds of objects, such a canonical name may simply not exist. For example, consider the elements of a list. The elements in the list are not individually named, and it is entirely possible that the only way to refer to them in a program is by using list indices on the containing list. If such a list of objects was passed into your function, you could not possibly assign meaningful identifiers to the values.

Python doesn't save the name on the left hand side of an assignment into the assigned object because:

  1. It would require figuring out which name was "canonical" among multiple conflicting objects,
  2. It would make no sense for objects which are never assigned to an explicit variable name,
  3. It would be extremely inefficient,
  4. Literally no other language in existence does that.

So, for example, functions defined using lambda will always have the "name" <lambda>, rather than a specific function name.

The best approach would be simply to ask the caller to pass in an (optional) list of names. If typing the '...','...' is too cumbersome, you could accept e.g. a single string containing a comma-separated list of names (like namedtuple does).


I think it's so difficult to do this in Python because of the simple fact that you never will not know the name of the variable you're using. So, in his example, you could do:

Instead of:

list_of_dicts = [n_jobs, users, queues, priorities]

dict_of_dicts = {"n_jobs" : n_jobs, "users" : users, "queues" : queues, "priorities" : priorities}

just another way to do this based on the content of input variable:

(it returns the name of the first variable that matches to the input variable, otherwise None. One can modify it to get all variable names which are having the same content as input variable)

def retrieve_name(x, Vars=vars()):
    for k in Vars:
        if type(x) == type(Vars[k]):
            if x is Vars[k]:
                return k
    return None

This function will print variable name with its value:

import inspect

def print_this(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    print(str([k for k, v in callers_local_vars if v is var][0])+': '+str(var))
***Input & Function call:***
my_var = 10

print_this(my_var)

***Output**:*
my_var: 10

If the goal is to help you keep track of your variables, you can write a simple function that labels the variable and returns its value and type. For example, suppose i_f=3.01 and you round it to an integer called i_n to use in a code, and then need a string i_s that will go into a report.

def whatis(string, x):
    print(string+' value=',repr(x),type(x))
    return string+' value='+repr(x)+repr(type(x))
i_f=3.01
i_n=int(i_f)
i_s=str(i_n)
i_l=[i_f, i_n, i_s]
i_u=(i_f, i_n, i_s)

## make report that identifies all types
report='\n'+20*'#'+'\nThis is the report:\n'
report+= whatis('i_f ',i_f)+'\n'
report+=whatis('i_n ',i_n)+'\n'
report+=whatis('i_s ',i_s)+'\n'
report+=whatis('i_l ',i_l)+'\n'
report+=whatis('i_u ',i_u)+'\n'
print(report)

This prints to the window at each call for debugging purposes and also yields a string for the written report. The only downside is that you have to type the variable twice each time you call the function.

I am a Python newbie and found this very useful way to log my efforts as I program and try to cope with all the objects in Python. One flaw is that whatis() fails if it calls a function described outside the procedure where it is used. For example, int(i_f) was a valid function call only because the int function is known to Python. You could call whatis() using int(i_f**2), but if for some strange reason you choose to define a function called int_squared it must be declared inside the procedure where whatis() is used.


For constants, you can use an enum, which supports retrieving its name.


I try to get name from inspect locals, but it cann't process var likes a[1], b.val. After it, I got a new idea --- get var name from the code, and I try it succ! code like below:

#direct get from called function code
def retrieve_name_ex(var):
    stacks = inspect.stack()
    try:
        func = stacks[0].function
        code = stacks[1].code_context[0]
        s = code.index(func)
        s = code.index("(", s + len(func)) + 1
        e = code.index(")", s)
        return code[s:e].strip()
    except:
        return ""

You can try the following to retrieve the name of a function you defined (does not work for built-in functions though):

import re
def retrieve_name(func):
    return re.match("<function\s+(\w+)\s+at.*", str(func)).group(1)

def foo(x):
    return x**2

print(retrieve_name(foo))
# foo

참고URL : https://stackoverflow.com/questions/18425225/getting-the-name-of-a-variable-as-a-string

반응형