Есть ли встроенный способ определить функцию, которая принимает либо 1 аргумент, либо 3? - PullRequest
0 голосов
/ 12 ноября 2018

В Python есть ошибка при вызове встроенного type() без аргументов:

TypeError: type() takes 1 or 3 arguments

Как мы можем определить такой метод? Есть ли встроенный способ? Или нам нужно сделать что-то вроде этого:

>>> def one_or_three(*args):
...   if len(args) not in [1,3]:
...     raise TypeError("one_or_three() takes 1 or 3 arguments")
... 
>>> one_or_three(1)
>>> one_or_three()
TypeError: one_or_three() takes 1 or 3 arguments
>>> one_or_three(1,2)
TypeError: one_or_three() takes 1 or 3 arguments

Ответы [ 2 ]

0 голосов
/ 21 ноября 2018

Такое поведение вполне возможно в Python.

def one_or_three(one, two=object(), three=object()):
    two_sentinel, three_sentinel = one_or_three.__defaults__
    if (two == two_sentinel) != (three == three_sentinel):
        raise TypeError("one_or_three() takes 1 or 3 arguments")
    ...

Это имеет преимущества именованных аргументов (семантическое значение, передача по имени и т. Д.), Но в основном представляет собой вариант проверки значений некоторых переменных, чтобы узнать, были ли переданы одна или три вещи.

Обратите внимание, что два вызова object() создают два разных объекта и связывают их с функцией:

>>> one_or_three.__defaults__
(<object object at 0x00168540>, <object object at 0x00168ED0>)

Таким образом, они уникальны во всем мире. Если бы вместо этого вы использовали None в качестве вашего дозорного объекта, то было бы невозможно передать None в качестве аргумента (хотя, конечно, это может быть желательным).

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

Во-первых, type - это не нативный Python (по крайней мере, в CPython), а C.

Модуль inspect может легко подтвердить это (даже если задокументировано как встроенная функция, type реализован как класс в CPython):

>>> print(inspect.signature(type.__init__))
(self, /, *args, **kwargs)
>>> print(sig.parameters['self'].kind)
POSITIONAL_ONLY

Тип параметра POSITIONAL_ONLY, который не может быть создан в Python.

Это означает, что невозможно будет точно воспроизвести поведение типа.

Исходный код Python допускает только 2 подписи для переменного числа аргументов:

  • 3 параметра, 2 из которых являются необязательными:

    type(object_or_name, bases = None, dict = None)
    

    Это было бы совсем по-другому, потому что он с радостью примет type(obj, None), что определенно не то, что ожидается здесь

  • простой *args параметр, длина которого будет проверена вручную - ваше предложение. Это будет намного ближе к нативному поведению type, потому что оно действительно требует 1 или 3 параметра, независимо от значений.

TL / DR: ответ на ваш вопрос в том, что нам действительно нужно что-то подобное .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...