ограничение количества необязательных позиционных аргументов для функции / метода - PullRequest
1 голос
/ 12 ноября 2009

Каково подходящее решение для ограничения числа необязательных позиционных аргументов для функции или метода? Например. Я хотел бы иметь функцию, которая принимает два или три позиционных аргумента (но не больше). Я не могу использовать необязательный аргумент ключевого слова (потому что функция должна принимать неограниченное количество аргументов с произвольно названным ключевым словом). Пока я придумал что-то вроде этого:

def foo(x, y, *args, **kwargs):
    if len(args) == 1:
        # do something
    elif len(args) > 1:
        raise TypeError, "foo expected at most 3 arguments, got %d" % (len(args) + 2)
    else
        # do something else

Это разумно или есть лучший способ?

Ответы [ 5 ]

2 голосов
/ 12 ноября 2009

Один из способов выяснить, что считать «pythonic», - это поиск примеров в самом исходном коде python.

find '/usr/lib/python2.6' -name '*.py' -exec egrep 'len\(args\)' {} + | wc
    156     867   12946

Если вы внимательно изучите результаты вышеуказанной команды (без wc), вы найдете множество примеров, использующих именно ту методику, которую вы предлагаете.

2 голосов
/ 12 ноября 2009

это работает:

>>> def foo(a, b, c=3, **kwargs):
    print(a, b, c, kwargs)


>>> foo(3, 4, 2)
3 4 2 {}
>>> foo(3, 4)
3 4 3 {}
1 голос
/ 12 ноября 2009

Вы можете написать декоратор:

class TooManyArgumentsException(Exception):
    pass

def limit_args(n):
    def limit_decorator(f):
        def new_f(*args, **kwargs):
            if len(args) > n:
                raise TooManyArgumentsException("%d args accepted at most, %d args passed" % (n, len(args)))
            return f(*args, **kwargs)
        return new_f
    return limit_decorator

А затем используйте это так:

>>> @limit_args(5)
... def f(a, b, *args):
...     return a + b + sum(args)
...
>>> f(1, 2, 3)
6
>>> f(1, 2, 3, 4)
10
>>> f(1, 2, 3, 4, 5)
15
>>> f(1, 2, 3, 4, 5, 6)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "limit.py", line 8, in new_f
    raise TooManyArgumentsException("%d args accepted at most, %d args passed" % (n, len(args)))
limit.TooManyArgumentsException: 5 args accepted at most, 6 args passed
>>> 
1 голос
/ 12 ноября 2009

Ваше решение мне кажется разумным.

0 голосов
/ 12 ноября 2009

Это выглядит хорошо для меня.

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

def validate_num_args(num_args=None, num_kwargs=None):
    def entangle(f):
        def inner(*args, **kwargs):
            if not num_args is None and len(args) > num_args:
                raise ValueError("Too many arguments, got %s, wanted %s." % (len(args), num_args))
            if not num_kwargs is None and len(kwargs) > num_kwargs:
                raise ValueError("Too many keyword arguments, got %s, wanted %s." % (len(kwargs), num_kwargs))
            return f(*args, **kwargs)
        return inner
    return entangle

@validate_num_args(num_args=3)
def foo(x, y, *args, **kwargs):
    return "do something with these variables:", x, y, args, kwargs

print "Good:\n", foo(1,2,3)
print ""
print "Bad:\n", foo(1,2,3,4)

Вывод этого кода:

Good:
('do something with these variables:', 1, 2, (3,), {})

Bad:
Traceback (most recent call last):
  File "c:\so.py", line 18, in <module>
    print "Bad:\n", foo(1,2,3,4)
  File "c:\so.py", line 5, in inner
    raise ValueError("Too many arguments, got %s, wanted %s." % (num_args, len(args)))
ValueError: Too many arguments, got 4, wanted 3.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...