변수 이름을 문자열로 얻기


173

이 스레드는 파이썬 에서 함수 이름을 문자열로 얻는 방법을 설명합니다 : 함수 이름을 문자열로 얻는 방법?

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

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

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

retrieve_name()들어이 목록에서 Pandas에서 DataFrame만들려면 함수 / 속성을 찾고 있습니다. 여기서 열 이름 은 실제 사전의 이름으로 지정됩니다.

# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [retrieve_name(d) for d in list_of_dicts] 

답변:


19

python-varname패키지를 사용하면 변수 이름을 쉽게 검색 할 수 있습니다

https://github.com/pwwang/python-varname

귀하의 경우 다음을 수행 할 수 있습니다.

from varname import Wrapper

foo = Wrapper(dict())

# foo.name == 'foo'
# foo.value == {}
foo.value['bar'] = 2

또는 변수 이름을 직접 검색 할 수도 있습니다.

from varname import nameof

foo = dict()

fooname = nameof(foo)
# fooname == 'foo'

이 패키지의 저자입니다. 질문이 있거나 github에 문제를 제출할 수 있으면 알려주십시오.


2
알았어, 마침내 알았어! 다음을 사용하여 설치 pip3 install python-varname==0.1.5; 다음을 사용하여 가져 from varname import nameof
오기

어떻게 든이 함수는 루프에서 작동하지 않습니다 : test = {} print(varname.nameof(test)) for i in [0]: print(varname.nameof(test))첫 번째 프린트는 test, 루프의 프린트는VarnameRetrievingError: Callee's node cannot be detected.
Tillus

1
@Tillus 고정v0.2.0
Panwen Wang

107

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

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


7
감사. 그러나 왜 파이썬은 함수를 위해 이것을합니까? (파이썬 즉, 하나의 유형은 객체)
아멜리오 바스케스 - 레이나

1
@kindall : 모듈을 잊지 마십시오 : 표준 이름도 있습니다. 또한, __name__항상 수정 될 수 있다는 것을 잊지 마십시오. 즉, "정식"이름은 객체를 얻는 데 사용할 수있는 이름이 아닐 수 있습니다 (예 : 동적으로 클래스를 만들 때).
nneonneo

8
@ scohe001이 보여주는 것처럼 "단순히 불가능합니다"라는 말은 거짓 입니다. 파이썬의 변수 이름 데이터베이스는 다른 관계형 DB와 마찬가지로 항상 "역"으로 관련 객체를 검색하고 주어진 변수에 대해 처음 찾은 또는 전체 유효한 변수 이름 집합을 반환 할 수 있습니다.
호브

3
@ hobs 당신은 기술적으로 정확합니다 ... 최고의 종류의 올바른 것입니다. 그러나 실제로는 객체에 대한 잠재적 이름이 너무 많아서 객체를 얻는 것보다 더 문제가 많습니다.
kindall

1
@kindall 당신의 "가치"임계 값이 O (1)이면 당신이 옳은 것 같아요. scohe001의 루프는 O (N)입니다.
호브

82

변수 값이 이름을 다시 가리 키지 않더라도 할당 된 모든 변수 목록과 해당 값에 액세스 할 수 있으므로 한 사람 만 var 이름을 찾기 위해 루핑을 제안한 것이 놀랍습니다.

그 대답에 대해 누군가가 스택을 걷고 모든 지역 및 전역을 찾아서 찾아야 할 수도 있다고 언급 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


1
@theodox 나는 절대적으로이 아마와 역할을하므로, 동의 import hooks, ironpythonjython
scohe001

5
작동하지 않습니다. 원자 변수에는 이름이 속성으로 없습니다. 당신은 그래서 경우 a, b = 2, 2, retrieve_name(a)그리고 retrieve_name(b)모두 반환 ['a', 'b']또는['b', 'a']
토마스

1
@tomas 사실, 그것은 255 이하의 정수가 기본적으로 싱글 톤 인 cPython의 최적화에 대한 구현 세부 사항입니다. 따라서 해당 값에 할당 된 변수 trueis비교를 위해 효과적으로 반환 됩니다.
Toote

1
전달 된 var의 이름을 가져 오는이 모드가 있습니까? 예를 들어 def foo(bar): retrieve_name(bar)항상 막대를 반환하지만 foo(baz)반환하려면 baz) 대신 bar?
SumNeuron

1
@SumNeuron callers_local_vars하나의 스코프를 더 뒤로 이동 하도록 할당 된 라인을 수정하면 호출중인 모든 범위를 볼 수 있습니다 foo. 행을로 변경하십시오 inspect.currentframe().f_back.f_back.f_locals.items()(추가에주의하십시오 f_back).
scohe001

37

Python 3.8에서는 간단히 f-string 디버깅 기능을 사용할 수 있습니다.

>>> foo = dict()
>>> f'{foo=}'.split('=')[0]
'foo' 

좋아요! 그리고 객체의 이름 대신 속성의 이름을 얻으려면f'{foo=}'.split('=')[0].split('.')[-1]
Mickael V.

30

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]

코드의 어느 곳에서나 유용합니다. 첫 번째 일치 항목을 찾은 역 스택을 트래버스합니다.


좋은 작업! 시도했지만 retrieve_name(SomeClass.some_attribute)작동하지 않습니다. 더 도와 줄 수 있습니까?
Nam G VU

이것은 부울 변수로 어려움을 겪습니다. 나는 다음과 같이 끝납니다stop_on_error
SumNeuron

26

나는 이것이 가능하다고 생각하지 않습니다. 다음 예제를 고려하십시오.

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

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


2
참조 카운트 를 확장하여 양방향 관계를 만들 수 있습니다 . 이 답변 (및 일부)은 구현을 제공합니다.
Shayaan

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

다음과 같이 사용됩니다.

name(variable=variable)

12
원하는 변수의 이름이 아니라 "변수"를 반환합니다. 예를 들어 - 사용 name(variable=variable)가 출력 ['variable']하고 사용하는 name(variable=another_variable)것입니다 하지 출력을 ['another_variable']것이 아니라 ['variable'].
DalyaG

1
실제로 예상대로 작동합니다. «variable»을 모두 변수로 바꾸면됩니다. 첫 번째 변수 이름의 문자열이 포함 된 단일 요소 목록을 반환합니다 . 예를 들어 >>> a = [] >>> b = a >>> name(a=b) ['a'] >>> name(b=a) ['b']`
Alguem Meugla

8

한 가지 방법이 있습니다. 나는 그것이 취하기 때문에 중요한 것에 대해서는 이것을 권장하지 않을 것입니다. 그러나 할 수 있습니다.

inspect모듈을 사용하여 호출 한 소스 코드를 찾는 함수를 작성하십시오 . 그런 다음 소스 코드를 구문 분석하여 검색하려는 변수 이름을 식별 할 수 있습니다. 예를 들어 autodict다음은 변수 목록을 가져 와서 변수 이름에 대한 사전 매핑 변수 이름을 반환하는 함수입니다. 예 :

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

줄 것이다 :

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

소스 코드 자체를 검사하는 것은 통해 검색하는 것보다 더 나은 locals()또는 globals()후자의 방법은 당신에게하지 않기 때문에 어떤 변수 당신이 원하는 사람입니다.

여하튼, 코드는 다음과 같습니다.

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

작업은으로 줄 inspect.getouterframes을 이루어 호출 된 코드 내의 문자열을 반환합니다 autodict.

이런 종류의 마술의 명백한 단점은 소스 코드가 어떻게 구성되는지에 대한 가정을한다는 것입니다. 물론 통역사 내부에서 실행되면 전혀 작동하지 않습니다.


안녕하세요, 저는 세가지 질문 만 있습니다 : 1. 왜 "1"입니까? 2. 왜 "4"입니까? 3. 왜 "0"입니까? :)
Piotr Wasilewicz

7

나는 이런 종류의 마술을 강력하게하기 위해 패키지 마법 을 썼다 . 당신은 쓸 수 있습니다:

from sorcery import dict_of

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

이를 데이터 프레임 생성자에 전달합니다. 다음과 같습니다.

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

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

자신의 함수를 작성하려면 지역에 정의 된 변수를 확인한 다음 전역을 확인할 수 있습니다. 아무것도 발견되지 않으면 id ()를 비교하여 변수가 메모리의 동일한 위치를 가리키는 지 확인할 수 있습니다.

변수가 클래스에 있으면 className을 사용할 수 있습니다. dict .keys () 또는 vars (self) 변수가 정의되어 있는지 확인하십시오.


이름이 발신자 프레임에 있으면 어떻게합니까? 그럼 당신은 스택을 걷는 모든 사람의 확인 바보 같은 일에있을 것 locals하고 globals... 아무도 실제로 존재하지 않는 경우에는 이름을 잘못 점점 위험이 있습니다. 실제로 유용한 이익을 얻지 못하는 것은 엄청난 일입니다.
nneonneo

전체 질문은 바보입니다 ...하지만 그가하고 싶었던 일이라면 가능합니다. 존재 여부를 확인하는 한 Globals (). setdefault (var, <new object of type (var))을 사용하여 아무것도 없을 때 무언가를 만들 수 있습니다. 나는 그가 원하는 것을 정확히 확신하지 못하지만 변수가 범위에 의해 유지된다는 것을 배우면 더 나은 것을 알아낼 수 있습니다.
blakev

3

Python에서 defand class키워드는 정의한 객체 (함수 또는 클래스)에 특정 이름을 바인딩합니다. 마찬가지로, 파일 시스템에서 특정이라고하는 모듈로 인해 모듈에 이름이 지정됩니다. 세 가지 경우 모두 문제의 객체에 "정식"이름을 지정하는 확실한 방법이 있습니다.

그러나 다른 종류의 객체의 경우 이러한 표준 이름이 존재하지 않을 수 있습니다 . 예를 들어 목록의 요소를 고려하십시오. 목록의 요소는 개별적으로 이름이 지정되지 않으며 프로그램에서 해당 요소를 참조하는 유일한 방법은 포함 목록의 목록 색인을 사용하는 것입니다. 이러한 객체 목록이 함수에 전달 된 경우 값에 의미있는 식별자를 할당 할 수 없습니다.

Python은 다음과 같은 이유로 할당의 왼쪽에있는 이름을 할당 된 객체에 저장하지 않습니다.

  1. 충돌하는 여러 객체 중에서 "정식"인 이름을 파악해야합니다.
  2. 명시 적 변수 이름에 할당되지 않은 객체는 의미가 없습니다.
  3. 매우 비효율적입니다.
  4. 말 그대로 존재하는 다른 언어는 없습니다.

예를 들어, 사용하여 정의 된 함수는 특정 함수 이름이 아닌 lambda항상 "name"을 갖습니다 <lambda>.

가장 좋은 방법은 호출자에게 (선택적) 이름 목록을 전달하도록 요청하는 것입니다. 를 입력하는 '...','...'것이 너무 번거로운 경우 예를 들어 쉼표로 구분 된 이름 목록이 포함 된 단일 문자열 (예 :처럼 namedtuple)을 사용할 수 있습니다.


3
>> my_var = 5
>> my_var_name = [ k for k,v in locals().items() if v == my_var][0]
>> my_var_name 
'my_var'

locals ()-현재 범위의 로컬 변수가 포함 된 사전을 반환합니다. 이 사전을 반복함으로써 정의 된 변수와 동일한 값을 가진 키를 확인할 수 있습니다. 키를 추출하면 변수 텍스트를 문자열 형식으로 제공합니다.

(비트 변경 후) https://www.tutorialspoint.com/How-to-get-a-variable-name-as-a-string-in-Python


2

사용중인 변수의 이름을 절대 알 수 없다는 단순한 사실 때문에 파이썬 에서이 작업을 수행하는 것이 너무 어렵다고 생각합니다. 따라서 그의 예에서, 당신은 할 수 있습니다 :

대신에:

list_of_dicts = [n_jobs, users, queues, priorities]

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

2

입력 변수의 내용을 기반으로 이것을 수행하는 또 다른 방법 :

(입력 변수와 일치하는 첫 번째 변수의 이름을 반환합니다. 그렇지 않으면 None입니다. 입력 변수와 내용이 같은 모든 변수 이름을 가져 오도록 수정할 수 있습니다)

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

2

이 함수는 변수 이름을 값으로 인쇄합니다.

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

2

나는 방법이 있지만 가장 효율적이지 않지만 작동합니다! (그리고 그것은 멋진 모듈을 포함하지 않습니다).

기본적으로 변수의 IDglobals () 변수의 ID 와 비교 한 다음 일치하는 이름을 반환합니다.

def getVariableName(variable, globalVariables=globals().copy()):
    """ Get Variable Name as String by comparing its ID to globals() Variables' IDs

        args:
            variable(var): Variable to find name for (Obviously this variable has to exist)

        kwargs:
            globalVariables(dict): Copy of the globals() dict (Adding to Kwargs allows this function to work properly when imported from another .py)
    """
    for globalVariable in globalVariables:
        if id(variable) == id(globalVariables[globalVariable]): # If our Variable's ID matches this Global Variable's ID...
            return globalVariable # Return its name from the Globals() dict

1

목표를 통해 변수를 추적하는 데 도움이되는 경우 변수에 레이블을 지정하고 값과 유형을 반환하는 간단한 함수를 작성할 수 있습니다. 예를 들어, i_f = 3.01이라고 가정하고 코드에서 사용하기 위해 i_n이라는 정수로 반올림 한 다음 보고서에 들어갈 문자열 i_s가 필요합니다.

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)

이것은 디버깅 목적으로 각 호출에서 창에 인쇄하고 기록 된 보고서에 대한 문자열을 생성합니다. 유일한 단점은 함수를 호출 할 때마다 변수를 두 번 입력해야한다는 것입니다.

나는 파이썬 초보자이며 프로그래밍하고 파이썬의 모든 객체에 대처하려고 노력하면서 내 노력을 기록하는 매우 유용한 방법을 찾았습니다. 한 가지 결함은 whatis ()가 사용되는 프로 시저 외부에서 설명 된 함수를 호출하면 whatis ()가 실패한다는 것입니다. 예를 들어, int (i_f)는 int 함수가 Python에 알려져 있기 때문에 유효한 함수 호출이었습니다 . int (i_f ** 2)를 사용하여 whatis ()를 호출 할 수 있지만 이상한 이유로 int_squared라는 함수를 정의하기로 선택한 경우 whatis ()가 사용되는 프로 시저 내에서 선언해야합니다.


1

아마도 이것이 유용 할 수 있습니다.

def Retriever(bar):
    return (list(globals().keys()))[list(map(lambda x: id(x), list(globals().values()))).index(id(bar))]

이 함수는 전역 범위에서 값의 ID 목록을 살펴보고 (네임 스페이스를 편집 할 수 있음) 해당 ID를 기준으로 원하는 / 필요한 var 또는 함수의 인덱스를 찾은 다음 전역 이름 목록에서 이름을 반환합니다. 취득한 지수에.


1

다음 방법은 변수 이름을 반환하지 않지만이 방법을 사용하면 전역 범위에서 변수를 사용할 수있는 경우 데이터 프레임을 쉽게 만들 수 있습니다.

class CustomDict(dict):
    def __add__(self, other):
        return CustomDict({**self, **other})

class GlobalBase(type):
    def __getattr__(cls, key):
        return CustomDict({key: globals()[key]})

    def __getitem__(cls, keys):
        return CustomDict({key: globals()[key] for key in keys})

class G(metaclass=GlobalBase):
    pass

x, y, z = 0, 1, 2

print('method 1:', G['x', 'y', 'z']) # Outcome: method 1: {'x': 0, 'y': 1, 'z': 2}
print('method 2:', G.x + G.y + G.z) # Outcome: method 2: {'x': 0, 'y': 1, 'z': 2}

A = [0, 1]
B = [1, 2]
pd.DataFrame(G.A + G.B) # It will return a data frame with A and B columns

0

상수의 경우 이름 검색을 지원하는 열거 형을 사용할 수 있습니다.


0

로컬 검사에서 이름을 가져 오려고하지만 var like a [1], b.val을 처리 할 수 ​​없습니다. 그 후, 새로운 아이디어를 얻었습니다 --- 코드에서 var 이름을 가져 와서 succ! 아래와 같은 코드 :

#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 ""

0

정의한 함수의 이름을 검색하기 위해 다음을 시도 할 수 있습니다 (내장 함수에는 작동하지 않음).

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.