предотвратить опечатки в аргументах переменных ключевых слов

В Python3 я могу сделать (спасибо pep 3102):

def some_fun(a, *args, log=None, verbose=0):
    pass

и будьте уверены, что если я вызову это с помощью:

some_fun(1, 2, 3, lob=debug_log)

Я получаю ошибку типа в неожиданном ключевом аргументе lob.

В Python2 я не могу определить some_fun() с аргументами, состоящими только из ключевых слов, после произвольного списка аргументов. Я должен сделать:

def some_fun(a, *args, **kw):
    log  = kw.get("log", None)
    verbose = kw.get("verbose", 0)

все это прекрасно работает при правильном вызове, но я хотел бы получить ошибку типа, как и в случае с Python3, когда я предоставляю один или несколько неправильных аргументов ключевого слова для some_fun().


person Snake    schedule 01.02.2015    source источник


Ответы (3)


Вместо использования .get() для извлечения значений используйте .pop() и проверьте, пусто ли kw после извлечения всех аргументов, состоящих только из ключевых слов.

Для этого я использую небольшую вспомогательную функцию:

def check_empty_kwargs(kwargs):
   import inspect
   try:
      keys = kwargs.keys()
      assert len(keys) == 0
   except AssertionError:
      # uncomment if you want only one of the unexpected kwargs in the msg
      # keys = keys[:1]
      msg = "{0}() got an unexpected keyword argument{1} {2}".format(
         inspect.stack()[1][3], # caller name
         's' if len(keys) > 1 else '',
         ', '.join(["'{0}'".format(k) for k in keys]))
      raise TypeError(msg)

И вы бы использовали его как:

def some_fun(a, *args, **kw):
    log  = kw.pop("log", None)
    verbose = kw.pop("verbose", 0)
    check_empty_kwargs(kw)

вызывая это с помощью (при условии, что debug_log определено)

some_fun(1, 2, 3, lob=debug_log)
....
TypeError: some_fun() got an unexpected keyword argument 'lob'

Трассировка (конечно) будет отличаться от Python3.

person Anthon    schedule 01.02.2015

Вы можете проверить разрешенные ключи, например:

def f(a, *args, **kwargs):
    surplus = set(kwargs).difference(('log', 'foo', 'bar'))
    if surplus:
        raise TypeError('got unexpected keyword argument(s): ' + ', '.join(surplus))
person Jon Clements♦    schedule 01.02.2015
comment
Это работает. Я постараюсь проголосовать за это, как только у меня будет достаточно репутации. - person Snake; 01.02.2015

Если у вас есть куча шагов обработки, вы можете комбинировать вышеуказанные методы с еще одним:

def f(a, *args, **kwargs):
    # we allow xyz, a, b
    xyz = kwargs.pop('xyz', 1)
    # now xyz must be gone, so we can only have a and/or b
    others = (lambda a=1, b=2: (a, b)(**kwargs))
    # either that was ok or it failed
    return xyz, others
person glglgl    schedule 01.02.2015