키워드 인수를 얻는 것은 실제로 Python 방법으로 전달되었습니다.

StackOverflow https://stackoverflow.com/questions/1408818

  •  05-07-2019
  •  | 
  •  

문제

나는 명백한 키워드 args가있는 파이썬 방법을 꿈꾸고 있습니다.

def func(a=None, b=None, c=None):
    for arg, val in magic_arg_dict.items():   # Where do I get the magic?
        print '%s: %s' % (arg, val)

나는 발신자가 실제로 그 방법에 전달한 주장에 대한 사전을 얻고 싶다. **kwargs, 그러나 나는 발신자가 오래된 임의의 args를 통과 할 수 있기를 원하지 않습니다. **kwargs.

>>> func(b=2)
b: 2
>>> func(a=3, c=5)
a: 3
c: 5

그래서 : 그런 약자가 있습니까? 제 경우에는 각 인수와 비교하여 다른 인수를 비교하여 다른 주장을 찾을 수 있지만, 이것은 9 가지 논쟁이있을 때 부적절하며 지루합니다. 보너스 포인트의 경우 발신자가 키워드 인수를 통과 할 때에도 기본값을 할당 할 때에도 알려주는 안학을 제공합니다.

>>> func(a=None)
a: None

교활한!

편집하다: (어휘) 함수 서명은 그대로 유지되어야합니다. 그것은 공개 API의 일부이며, 명백한 키워드 Args의 주요 가치는 다큐멘터리 가치에 있습니다. 일을 흥미롭게 만들기 위해. :)

도움이 되었습니까?

해결책

나는 Lost-Ather의 데코레이터의 장점에서 영감을 받았으며, 그것과 약간의 놀면서 이것을 생각해 냈습니다.

def actual_kwargs():
    """
    Decorator that provides the wrapped function with an attribute 'actual_kwargs'
    containing just those keyword arguments actually passed in to the function.
    """
    def decorator(function):
        def inner(*args, **kwargs):
            inner.actual_kwargs = kwargs
            return function(*args, **kwargs)
        return inner
    return decorator


if __name__ == "__main__":

    @actual_kwargs()
    def func(msg, a=None, b=False, c='', d=0):
        print msg
        for arg, val in sorted(func.actual_kwargs.iteritems()):
            print '  %s: %s' % (arg, val)

    func("I'm only passing a", a='a')
    func("Here's b and c", b=True, c='c')
    func("All defaults", a=None, b=False, c='', d=0)
    func("Nothin'")
    try:
        func("Invalid kwarg", e="bogon")
    except TypeError, err:
        print 'Invalid kwarg\n  %s' % err

이것을 인쇄하는 것은 다음과 같습니다.

I'm only passing a
  a: a
Here's b and c
  b: True
  c: c
All defaults
  a: None
  b: False
  c: 
  d: 0
Nothin'
Invalid kwarg
  func() got an unexpected keyword argument 'e'

나는 이것에 만족한다. 보다 유연한 접근 방식은 '실제_kwargs'로 하드 코딩하는 대신 데코레이터에 사용하려는 속성의 이름을 전달하는 것입니다. 그러나 이것은 솔루션을 보여주는 가장 간단한 접근법입니다.

음, 파이썬은 맛있습니다.

다른 팁

가장 쉽고 간단한 방법은 다음과 같습니다.

def func(a=None, b=None, c=None):
    args = locals().copy()
    print args

func(2, "egg")

이것은 출력을 제공합니다. {'a': 2, 'c': None, 'b': 'egg'}. 이유 args 사본이어야합니다 locals 사전은 사전이 변이 가능하다는 것입니다. 따라서이 기능에서 로컬 변수를 만든 경우 args 인수뿐만 아니라 모든 로컬 변수와 그 값을 포함합니다.

내장에 대한 더 많은 문서 locals 기능 여기.

하나의 가능성 :

def f(**kw):
  acceptable_names = set('a', 'b', 'c')
  if not (set(kw) <= acceptable_names):
    raise WhateverYouWantException(whatever)
  ...proceed...

IOW, 통과 된 이름이 허용 가능한 세트 내에 있는지 확인하기가 매우 쉽고 Python이 올라 가기를 원하는 것을 올리려고합니다 (TypeError, I '는 추측 ;-). 데코레이터로 바꾸기가 매우 쉽습니다. BTW.

또 다른 가능성 :

_sentinel = object():
def f(a=_sentinel, b=_sentinel, c=_sentinel):
   ...proceed with checks `is _sentinel`...

독특한 물건을 만들어 _sentinel 발신자가 우연히 통과 할 수있는 위험을 제거합니다. None (또는 발신자가 통과 할 수있는 다른 비 유니 키 기본값 값). 이게 전부입니다 object() BTW : 우연히 다른 물체와 혼동 될 수없는 극도로 조중 중량의 고유 한 센티넬에 좋습니다 ( is 운영자).

약간 다른 문제의 경우 두 솔루션 중 하나가 바람직합니다.

데코레이터를 사용하여 들어오는 kwargs를 검증하는 것은 어떻습니까?

def validate_kwargs(*keys):
    def entangle(f):
        def inner(*args, **kwargs):
            for key in kwargs:
                if not key in keys:
                    raise ValueError("Received bad kwarg: '%s', expected: %s" % (key, keys))
            return f(*args, **kwargs)
        return inner
    return entangle

###

@validate_kwargs('a', 'b', 'c')
def func(**kwargs):
   for arg,val in kwargs.items():
       print arg, "->", val

func(b=2)
print '----'
func(a=3, c=5)
print '----'
func(d='not gonna work')

이 출력을 제공합니다.

b -> 2
----
a -> 3
c -> 5
----
Traceback (most recent call last):
  File "kwargs.py", line 20, in <module>
    func(d='not gonna work')
  File "kwargs.py", line 6, in inner
    raise ValueError("Received bad kwarg: '%s', expected: %s" % (key, keys))
ValueError: Received bad kwarg: 'd', expected: ('a', 'b', 'c')

이것은 참고 자료의 단일 인스턴스로 가장 쉽게 달성됩니다.

# Top of module, does not need to be exposed in __all__
missing = {}

# Function prototype
def myFunc(a = missing, b = missing, c = missing):
    if a is not missing:
        # User specified argument a
    if b is missing:
        # User did not specify argument b

이 접근법의 좋은 점은 우리가 "IS"연산자를 사용하고 있기 때문에 발신자는 공허한 덕트를 인수 값으로 전달할 수 있으며, 우리는 여전히 그것을 통과하려는 의미가 아니라는 것을 알게 될 것입니다. 우리는 또한 이런 식으로 불쾌한 데코레이터를 피하고 코드를 조금 더 깨끗하게 유지합니다.

이 작업을 수행하는 더 좋은 방법이있을 것입니다. 그러나 여기에 내 테이크가 있습니다.

def CompareArgs(argdict, **kwargs):
    if not set(argdict.keys()) <= set(kwargs.keys()):
        # not <= may seem weird, but comparing sets sometimes gives weird results.
        # set1 <= set2 means that all items in set 1 are present in set 2
        raise ValueError("invalid args")

def foo(**kwargs):
    # we declare foo's "standard" args to be a, b, c
    CompareArgs(kwargs, a=None, b=None, c=None)
    print "Inside foo"


if __name__ == "__main__":
    foo(a=1)
    foo(a=1, b=3)
    foo(a=1, b=3, c=5)
    foo(c=10)
    foo(bar=6)

그리고 출력 :

Inside foo
Inside foo
Inside foo
Inside foo
Traceback (most recent call last):
  File "a.py", line 18, in 
    foo(bar=6)
  File "a.py", line 9, in foo
    CompareArgs(kwargs, a=None, b=None, c=None)
  File "a.py", line 5, in CompareArgs
    raise ValueError("invalid args")
ValueError: invalid args

이것은 아마도 데코레이터로 변환 될 수 있지만 내 장식자는 작업이 필요합니다. 독자에게 운동으로 떠났다 : p

아마도 *args를 통과하면 오류를 제기할까요?

def func(*args, **kwargs):
  if args:
    raise TypeError("no positional args allowed")
  arg1 = kwargs.pop("arg1", "default")
  if kwargs:
    raise TypeError("unknown args " + str(kwargs.keys()))

varname 목록이나 일반 구문 분석 기능을 사용하는 것이 간단합니다. 이것을 데코레이터 (Python 3.1)로 만드는 것은 너무 어렵지 않을 것입니다.

def OnlyKwargs(func):
  allowed = func.__code__.co_varnames
  def wrap(*args, **kwargs):
    assert not args
    # or whatever logic you need wrt required args
    assert sorted(allowed) == sorted(kwargs)
    return func(**kwargs)

참고 : 이것이 이미 포장 된 기능이나 기능을 얼마나 잘 작동 시킬지 잘 모르겠습니다. *args 또는 **kwargs 이미.

마법은 대답이 아닙니다.

def funky(a=None, b=None, c=None):
    for name, value in [('a', a), ('b', b), ('c', c)]:
        print name, value
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top