함수가받는 키워드 인수를 나열 할 수 있습니까?


104

키 / 값을 키워드 인수로 전달해야하는 사전이 있습니다. 예를 들어 ..

d_args = {'kw1': 'value1', 'kw2': 'value2'}
example(**d_args)

이것은 잘 작동 하지만 d_args dict에 example함수에서 허용하지 않는 값이 있으면 분명히 죽습니다. 예제 함수가 다음과 같이 정의되면def example(kw2):

d_args, 또는 example함수 의 생성을 제어하지 않기 때문에 이것은 문제입니다 . 둘 다 외부 모듈에서 가져오고 exampledict의 키워드 인수 중 일부만 허용합니다.

이상적으로는 그냥 할 것입니다

parsed_kwargs = feedparser.parse(the_url)
valid_kwargs = get_valid_kwargs(parsed_kwargs, valid_for = PyRSS2Gen.RSS2)
PyRSS2Gen.RSS2(**valid_kwargs)

유효한 키워드 인수 목록에서 dict를 필터링 할 것입니다.하지만 궁금한 점이 있습니다. 특정 함수가 취하는 키워드 인수를 프로그래밍 방식으로 나열하는 방법이 있습니까?

답변:


150

코드 객체를 직접 검사하고 변수를 처리하는 것보다 조금 더 좋은 방법은 inspect 모듈을 사용하는 것입니다.

>>> import inspect
>>> def func(a,b,c=42, *args, **kwargs): pass
>>> inspect.getargspec(func)
(['a', 'b', 'c'], 'args', 'kwargs', (42,))

특정 인수 세트로 호출 가능 여부를 알고 싶다면 기본값이 이미 지정되지 않은 인수가 필요합니다. 다음을 통해 얻을 수 있습니다.

def getRequiredArgs(func):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if defaults:
        args = args[:-len(defaults)]
    return args   # *args and **kwargs are not required, so ignore them.

그런 다음 특정 사전에서 누락 된 것을 알려주는 기능은 다음과 같습니다.

def missingArgs(func, argdict):
    return set(getRequiredArgs(func)).difference(argdict)

마찬가지로 잘못된 인수를 확인하려면 다음을 사용하십시오.

def invalidArgs(func, argdict):
    args, varargs, varkw, defaults = inspect.getargspec(func)
    if varkw: return set()  # All accepted
    return set(argdict) - set(args)

따라서 호출 가능한 경우 전체 테스트는 다음과 같습니다.

def isCallableWithArgs(func, argdict):
    return not missingArgs(func, argdict) and not invalidArgs(func, argdict)

(이것은 파이썬의 arg 파싱에 한해서만 좋습니다. kwargs에서 유효하지 않은 값에 대한 런타임 검사는 분명히 감지 할 수 없습니다.)


좋은! 이 기능을 몰랐습니다!
DzinX

1
코드 객체를 사용하는 방법이 다소 동일하다는 점을 감안할 때 모듈을 하나 더 가져와야하는 이점이 있습니까?
jmetz

@jmets-확실히-거의 항상 라이브러리 모듈을 사용하는 것이 자신의 것을 롤링하는 것보다 낫습니다. 또한 코드 객체의 속성은 더 내부적이며 변경 될 예정 입니다 (예 : pyhon3의 코드 로 이동 됨). 모듈을 인터페이스로 사용하면 이러한 내부 요소 중 일부가 변경 될 경우에 대비하여 좀 더 미래를 보장 할 수 있습니다. 또한 검사 할 수없는 함수 (예 : C 함수)에 대해 적절한 유형 오류를 던지는 것과 같이 생각하지 못했던 작업도 수행합니다.
Brian

13
inspect.getargspec(f)Python 3.0부터 사용되지 않습니다. 현대적인 방법은 inspect.signature(f).
gerrit

참고로 Cython 및 Python을 지원하려는 경우이 메서드는 Cython'd 함수에서 작동하지 않습니다. 반면 co_varnames에이 옵션은 두 가지 모두에서 작동합니다.
partofthething 2017-06-05

32

모든 통과 가능한 인수, 키워드 및 비 키워드 인수의 이름을 인쇄합니다.

def func(one, two="value"):
    y = one, two
    return y
print func.func_code.co_varnames[:func.func_code.co_argcount]

첫 번째 co_varnames는 항상 매개 변수 이기 때문입니다 (다음은 y위의 예 와 같이 지역 변수입니다 ).

이제 함수를 가질 수 있습니다.

def getValidArgs(func, argsDict):
    '''Return dictionary without invalid function arguments.'''
    validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
    return dict((key, value) for key, value in argsDict.iteritems() 
                if key in validArgs)

다음과 같이 사용할 수 있습니다.

>>> func(**getValidArgs(func, args))

편집 : 작은 추가 : 함수의 키워드 인수 만 필요한 경우func_defaults 속성을 사용하여 추출 할 수 있습니다.

def getValidKwargs(func, argsDict):
    validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
    kwargsLen = len(func.func_defaults) # number of keyword arguments
    validKwargs = validArgs[-kwargsLen:] # because kwargs are last
    return dict((key, value) for key, value in argsDict.iteritems() 
                if key in validKwargs)

이제 알려진 인수를 사용하여 함수를 호출 할 수 있지만 추출 된 kwargs, 예 :

func(param1, param2, **getValidKwargs(func, kwargsDict))

이것은 서명에 funcno *args또는 **kwargsmagic 을 사용 한다고 가정합니다 .


"키워드"인수 "키"만 출력하려면 어떻게해야합니까?
Jia

7

Python 3.0 :

>>> import inspect
>>> import fileinput
>>> print(inspect.getfullargspec(fileinput.input))
FullArgSpec(args=['files', 'inplace', 'backup', 'bufsize', 'mode', 'openhook'],
varargs=None, varkw=None, defaults=(None, 0, '', 0, 'r', None), kwonlyargs=[], 
kwdefaults=None, annotations={})

7

Python 3 솔루션의 경우 알고 싶은 매개 변수의 종류에inspect.signature 따라 사용 하고 필터링 할 수 있습니다 .

위치 또는 키워드, 키워드 전용, var 위치 및 var 키워드 매개 변수가있는 샘플 함수 가져 오기 :

def spam(a, b=1, *args, c=2, **kwargs):
    print(a, b, args, c, kwargs)

이에 대한 서명 개체를 만들 수 있습니다.

from inspect import signature
sig =  signature(spam)

그런 다음 목록 이해력으로 필터링하여 필요한 세부 정보를 찾습니다.

>>> # positional or keyword
>>> [p.name for p in sig.parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD]
['a', 'b']
>>> # keyword only
>>> [p.name for p in sig.parameters.values() if p.kind == p.KEYWORD_ONLY]
['c']

유사하게, var 위치의 경우 using p.VAR_POSITIONAL및 var 키워드 with VAR_KEYWORD.

또한 if에 절을 추가하여 p.default같음 여부를 확인하여 기본값이 있는지 확인할 수 p.empty있습니다.


3

DzinX의 답변 확장 :

argnames = example.func_code.co_varnames[:func.func_code.co_argcount]
args = dict((key, val) for key,val in d_args.iteritems() if key in argnames)
example(**args)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.