Определите, был ли передан именованный параметр - PullRequest
14 голосов
/ 01 ноября 2008

Я хотел бы знать, возможно ли определить, был ли передан параметр функции со значением по умолчанию в Python. Например, как работает dict.pop?

>>> {}.pop('test')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'pop(): dictionary is empty'
>>> {}.pop('test',None)
>>> {}.pop('test',3)
3
>>> {}.pop('test',NotImplemented)
NotImplemented

Как метод pop определяет, что в первый раз возвращаемое значение по умолчанию не было передано? Это то, что можно сделать только в C?

Спасибо

Ответы [ 5 ]

11 голосов
/ 01 ноября 2008

Соглашение часто заключается в использовании arg=None и использовании

def foo(arg=None):
    if arg is None:
        arg = "default value"
        # other stuff
    # ...

чтобы проверить, прошло ли оно или нет. Разрешение пользователю передать None, что будет интерпретировано, как если бы аргумент был , а не передан.

8 голосов
/ 01 ноября 2008

Полагаю, вы имеете в виду «аргумент ключевого слова», когда говорите «именованный параметр». dict.pop() не принимает аргумент ключевого слова, так что эта часть вопроса является спорной.

>>> {}.pop('test', d=None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pop() takes no keyword arguments

Тем не менее, способ определить, был ли предоставлен аргумент, - это использовать синтаксис *args или **kwargs. Например:

def foo(first, *rest):
    if len(rest) > 1:
        raise TypeError("foo() expected at most 2 arguments, got %d"
                        % (len(rest) + 1))
    print 'first =', first
    if rest:
        print 'second =', rest[0]

С некоторой работой, а также с использованием синтаксиса **kwargs можно полностью эмулировать соглашение о вызовах python, где аргументы могут быть предоставлены либо по позиции, либо по имени, а аргументы, предоставленные несколько раз (по позиции и имени), вызывают ошибка.

2 голосов
/ 01 ноября 2008
def f(one, two=2):
   print "I wonder if", two, "has been passed or not..."

f(1, 2)

Если это точное значение вашего вопроса, я думаю, что нет никакого способа различить 2, которое было в значении по умолчанию, и 2, которое было передано. Я не нашел, как добиться такого различия даже в модуле inspect .

2 голосов
/ 01 ноября 2008

Вы можете сделать это так:

def isdefarg(*args):
    if len(args) > 0:
        print len(args), "arguments"
    else:
        print "no arguments"

isdefarg()
isdefarg(None)
isdefarg(5, 7)

См. Документацию Python по звонкам для полной информации.

1 голос
/ 01 ноября 2008

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

def fun(arg=Ellipsis):
    if arg is Ellipsis:
        print "No arg provided"
    else:
        print "arg provided:", repr(arg)

это делает то, что вы хотите? Если нет, то, как предлагали другие, вы должны объявить свою функцию с синтаксисом *args, **kwargs и проверить в параметре kwargs наличие параметра.

...