이름 (문자열)을 사용하여 모듈의 함수 호출


1734

파이썬 프로그램에서 함수 이름을 가진 문자열이 주어진 함수를 호출하는 가장 좋은 방법은 무엇입니까? 예를 들어 모듈 foo이 있고 내용이 인 문자열이 있다고 가정 해 봅시다 "bar". 전화하는 가장 좋은 방법은 무엇입니까 foo.bar()?

함수의 반환 값을 가져와야하므로을 사용하지 않는 것 eval입니다. eval해당 함수 호출의 결과를 반환하는 임시 함수를 정의 하여 사용하는 방법을 알아 냈지만 더 우아한 방법이 있기를 바랍니다.

답변:


2078

foo방법으로 모듈 을 가정 bar:

import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()

2 행과 3 행을 다음과 같이 단축 할 수 있습니다.

result = getattr(foo, 'bar')()

사용 사례에 더 적합한 경우

getattr이런 방식으로 클래스 인스턴스 바운드 메서드, 모듈 수준 메서드, 클래스 메서드 등을 사용할 수 있습니다 . 목록은 계속됩니다.


9
hasattr 또는 getattr을 사용하여 함수가 정의되어 있는지 확인할 수 있습니다. 나는 데이터베이스 매핑 (eventType과 handling functionName)을 가지고 있었고, 파이썬에서 이벤트 핸들러를 정의하는 것을 결코 잊어 버리지 않기를 원했다
Shaun

9
모듈 이름을 이미 알고있는 경우 작동합니다. 그러나 사용자가 모듈 이름을 문자열로 제공하도록하려면 작동하지 않습니다.
Blairg23

7
NoneType을 호출 할 수없는 예외를 피해야하는 경우 getattr의 세 가지 인수 형식 인 getattr (foo, 'bar', lambda : None)을 사용할 수도 있습니다. 형식에 대해 사과드립니다. stackexchange 안드로이드 앱은 끔찍합니다.
geekofalltrades

3
로컬 / 현재 모듈의 기능에 대해서만 관심이 있다면 @sastanin이 제공하는 답변을 참조하십시오.
NuSkooler 2016 년

6
당신이 있다면 예 @akki, foo 모듈 당신은 사용할 수 있습니다 globals():이 할methodToCall = globals()['bar']
벤 호이트

543
locals()["myfunction"]()

또는

globals()["myfunction"]()

locals 는 현재 로컬 심볼 테이블이있는 사전을 반환합니다. globals 는 전역 기호 테이블이있는 사전을 반환합니다.


53
전역 / 로컬을 사용하는이 방법은 호출해야하는 방법이 호출하는 동일한 모듈에 정의되어 있으면 좋습니다.
Joelmob

@Joelmob 루트 네임 스페이스에서 문자열로 객체를 얻는 다른 방법이 있습니까?
Nick T

@ NickT 나는이 방법들만 알고 있습니다. 이들과 동일한 기능을 수행하는 다른 것들이 있다고 생각하지 않습니다. 적어도 더 많은 이유가 있다고 생각할 수는 없습니다.
Joelmob

나는 당신에게 이유가 있습니다 (실제로 나를 이끌어 낸 이유) : 모듈 A에는 이름으로 함수를 호출 해야하는 함수 F가 있습니다. 모듈 B는 모듈 A를 가져오고 모듈 B에 정의 된 함수 G 호출 요청으로 함수 F를 호출합니다. 분명히 함수 F는 모듈 F에 정의 된 전역으로 만 실행되므로 실패합니다. 따라서 globals () [ 'G'] = 없음
David Stein

337

패트릭의 해결책은 아마도 가장 깨끗할 것입니다. 동적으로 모듈을 선택해야하는 경우 다음과 같이 가져올 수 있습니다.

module = __import__('foo')
func = getattr(module, 'bar')
func()

93
나는 그 마지막 의견을 이해하지 못합니다. __import__에는 자체 권한이 있으며 언급 된 문서에서 다음 문장은 "런타임에 이름 만 알려진 모듈을 가져 오려는 경우를 제외하고 __import __ ()를 직접 사용하는 경우는 거의 없습니다"라고 말합니다. 주어진 답변에 +1.
hoffmaje

50
사용하십시오 importlib.import_module. 공식 문서는 다음과 같이 말합니다 __import__. "importlib.import_module ()과 달리 일상적인 파이썬 프로그래밍에는 필요하지 않은 고급 함수입니다." docs.python.org/2/library/functions.html#__import__
glarrain

8
@glarrain 2.7 이상 만 지원하면 괜찮습니다.
Xiong Chiamiov

1
@Xiong Chaimiov importlib.import_module는 3.6에서 지원됩니다. 참조 docs.python.org/3.6/library/...
cowlinator

7
@cowlinator 예, 3.6은 엄격한 버전 지정 의미론과 릴리스 날짜 (약 6 년 후)에서 "2.7 이상"의 일부입니다. 또한 내 의견 후 3 년 동안 존재하지 않았습니다. ;) 3.x 브랜치에서 모듈은 3.1 이후로 사용되었습니다. 2.7과 3.1은 이제 꽤 고대입니다. 2.6 만 지원하는 서버가 여전히 남아 있지만 요즘은 importlib를 표준 조언으로 사용할 가치가 있습니다.
Xiong Chiamiov

113

간단한 기여. 인스턴스화해야하는 클래스가 동일한 파일에 있으면 다음과 같이 사용할 수 있습니다.

# Get class from globals and create an instance
m = globals()['our_class']()

# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')

# Call it
func()

예를 들면 다음과 같습니다.

class A:
    def __init__(self):
        pass

    def sampleFunc(self, arg):
        print('you called sampleFunc({})'.format(arg))

m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')

# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')

그리고 수업이 아닌 경우 :

def sampleFunc(arg):
    print('you called sampleFunc({})'.format(arg))

globals()['sampleFunc']('sample arg')

100

함수에 대한 완전한 파이썬 경로가있는 문자열이 주어지면이 함수의 결과를 얻는 방법입니다.

import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()

1
이것은 나를 도왔다. 가벼운 버전의 __import__기능입니다.
Pankaj Bhambhani

이것이 가장 좋은 대답이라고 생각합니다.
Saeid

55

Python 프로그래밍 FAQ 에 따르면 가장 좋은 대답 은 다음과 같습니다.

functions = {'myfoo': foo.bar}

mystring = 'myfoo'
if mystring in functions:
    functions[mystring]()

이 기술의 주요 장점은 문자열이 함수 이름과 일치 할 필요가 없다는 것입니다. 이것은 또한 사례 구성을 에뮬레이트하는 데 사용되는 기본 기술입니다


43

아무도 원치 않는 대답

행동과 같은 평가

getattr(locals().get("foo") or globals().get("foo"), "bar")()

자동 가져 오기를 추가하지 않는 이유

getattr(
    locals().get("foo") or 
    globals().get("foo") or
    __import__("foo"), 
"bar")()

추가 사전이있는 경우 확인하고 싶습니다.

getattr(next((x for x in (f("foo") for f in 
                          [locals().get, globals().get, 
                           self.__dict__.get, __import__]) 
              if x)),
"bar")()

우리는 더 깊이 가야한다

getattr(next((x for x in (f("foo") for f in 
              ([locals().get, globals().get, self.__dict__.get] +
               [d.get for d in (list(dd.values()) for dd in 
                                [locals(),globals(),self.__dict__]
                                if isinstance(dd,dict))
                if isinstance(d,dict)] + 
               [__import__])) 
        if x)),
"bar")()

디렉토리 트리를 재귀 적으로 스캔하고 USB 드라이브를 자동 마운트하여 개선 할 수 있습니다.
윌크

27

가치있는 것을 위해 함수 (또는 클래스) 이름과 앱 이름을 문자열로 전달 해야하는 경우 다음을 수행 할 수 있습니다.

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)

좀 더 일반적인 것입니다handler = getattr(sys.modules[__name__], myFnName)
lony

21

이 시도. 이것은 여전히 ​​eval을 사용하지만 현재 컨텍스트에서 함수소환하는 데만 사용합니다 . 그런 다음 원하는대로 사용할 실제 기능이 있습니다.

이것의 주요 이점은 함수를 소환 할 때 평가 관련 오류가 발생한다는 것입니다. 그럼 당신은 얻을 것이다 단지 당신이 호출 할 때 기능 관련 오류를.

def say_hello(name):
    print 'Hello {}!'.format(name)

# get the function by name
method_name = 'say_hello'
method = eval(method_name)

# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)

1
이것은 위험합니다. 문자열은 무엇이든 가질 수 있으며 eval은 고려하지 않고 평가할 수 있습니다.
iankit

4
물론, 이러한 위험을 고려할 때 상황에 따라 사용중인 컨텍스트를 염두에 두어야합니다.
tvt173

1
함수는 매개 변수의 유효성을 검사 할 책임이 없습니다. 이는 다른 함수의 작업입니다. 문자열과 함께 eval을 사용하는 것이 위험하다고 말하는 것은 모든 기능을 사용하는 것이 위험하다는 것입니다.
red777

eval꼭 필요한 경우가 아니면 절대 사용 하지 마십시오 . getattr(__module__, method_name)이 맥락에서 훨씬 더 나은 선택입니다.
moi

14

제안 된 것 중 어느 것도 나를 도우 지 못했습니다. 나는 이것을 발견했다.

<object>.__getattribute__(<string name>)(<params>)

파이썬 2.66을 사용하고 있습니다

도움이 되었기를 바랍니다


13
getattr ()보다 어떤면에서 이것이 더 낫습니까?
V13

1
정확히 내가 원하는 것. 매력처럼 작동합니다! 완전한!! self.__getattribute__('title')self.title
ioaniatr와

self.__getattribute__('title')어쨌든 작동하지 않지만 (이유를 몰라) 결국 func = getattr(self, 'title'); func();작동합니다. 따라서 getattr()대신 사용하는 것이 좋습니다.
ioaniatr

10
파이썬을 모르는 사람들이이 정크를 피하는 것을 그만 둘 수 있습니까? getattr대신 사용하십시오 .
Aran-Fey

6

이 질문 과 같이 중복으로 표시된 변수 [duplicate]에 method-name 할당을 사용하여 클래스 내에서 메소드를 동적으로 호출하는 방법 에 관련 답변을 여기에 게시하고 있습니다.

시나리오는 클래스의 메소드가 동일한 클래스에서 다른 메소드를 동적으로 호출하려는 경우 더 넓은 시나리오와 명확성을 제공하는 원래 예제에 세부 정보를 추가했습니다.

class MyClass:
    def __init__(self, i):
        self.i = i

    def get(self):
        func = getattr(MyClass, 'function{}'.format(self.i))
        func(self, 12)   # This one will work
        # self.func(12)    # But this does NOT work.


    def function1(self, p1):
        print('function1: {}'.format(p1))
        # do other stuff

    def function2(self, p1):
        print('function2: {}'.format(p1))
        # do other stuff


if __name__ == "__main__":
    class1 = MyClass(1)
    class1.get()
    class2 = MyClass(2)
    class2.get()

출력 (Python 3.7.x)

기능 1:12

기능 2:12


-7

이것은 간단한 답변입니다. 예를 들어 화면을 지울 수 있습니다. 아래에는 eval 및 exec의 두 가지 예가 있으며, 청소 후 맨 위에 0을 인쇄하거나 (Windows를 사용하는 경우로 변경 clear하면 clsLinux 및 Mac 사용자는 그대로 두십시오) 또는 각각 실행합니다.

eval("os.system(\"clear\")")
exec("os.system(\"clear\")")

3
이것은 op가 요구하는 것이 아닙니다.
Tuncay Göncüoğlu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.