Количество аргументов фактической функции

Есть ли способ получить количество фактических параметров, переданных функции

def foo(a, optional=42): if ???? print "1 arg" else: print "2 args" foo(11) # should print 1 arg foo(22, 42) # should print 2 args 

без изменения его подписи, чтобы принять *args ?

Вы можете изменить значение по умолчанию для часового:

 _sentinel = object() def foo(a, optional=_sentinel): if optional is _sentinel: optional = 42 print "1 arg" else: print "2 args" 

или путем прямого доступа к нему в кортеже func_defaults :

 def foo(a, optional=object()): if optional is foo.func_defaults[0]: optional = 42 print "1 arg" else: print "2 args" 

но на самом деле не используют это; это будет просто запутать тех, кто не знаком со стандартными атрибутами объекта функции.

Да, объект _sentinel интроспективен и может быть получен еще определенным разработчиком, но затем тот же самый разработчик может просто обезвредить вашу функцию. 🙂

Вы можете использовать декоратор для этого. Из вопроса « Сохранять подписи украшенных функций» мы знаем, как это сделать правильно.

 import decorator @decorator.decorator def count_args(f): def new(*args, **kwargs): kwargs['nargs'] = len(args)+len(kwargs) return f(*args, **kwargs) return new @count_args def foo(a, optional=42, nargs=1): print nargs foo(1) # 1 foo(1, 4) # 2 foo(1, optional=4) # 2 

Обновить:

Я только что добавил аргумент ключевого слова для количества аргументов, которые мы передали функции. Как вы можете видеть, по умолчанию он равен 1, что является True. Это похоже на взлом, но он работает.

Я бы использовал декоратор:

 def wrapper(func): def wrapped(*args): if len(args) == 2: print "2 arg" else: print "1 arg" return wrapped @wrapper def foo(a,optional=None): pass foo(11) #1 arg foo(22, 42) #2 arg