Документирование параметров Python с утиным типом

У меня есть функция foobar, которая ожидает, что ее параметр baz будет любым объектом, реализующим __gt__ и __eq__.

def foobar(baz, qux):
    """
    :type baz: Any object that implements __gt__ and __eq__
    """
    if baz >= qux:
        return 'nice!'
    return 'ouch!'

Существуют ли какие-либо соглашения о том, как следует документировать эти типы параметров? Я использую Python 3.5, если это важно.

Вы можете добавить блок try-except для обработки ситуаций, когда вы не можете сравнивать объекты параметров и добавлять описание в документацию.

Lev Zakharov 03.09.2018 12:54

Также проверьте Сопоставимые типы с mypy.

Lev Zakharov 03.09.2018 12:55
object имеет атрибуты __eq__ и __gt__, так что разве ваш критерий не будет верным, пока вы достаточно глубоко погружаетесь в грязь?
timgeb 03.09.2018 13:14

@timgeb: Честно говоря, не подумал об этом, хороший момент. Вопрос действительно в том, чтобы задокументировать этот тип утиного набора текста, так что давайте представим, что это не так? :)

damd 03.09.2018 13:41

Вы добились некоторого прогресса?

timgeb 04.09.2018 10:26

@timgeb: Боюсь, что нет, я ценю, что вы нашли время ответить, но я не уверен, как это связано с вопросом о документировании типа параметра?

damd 04.09.2018 10:31

@damd, возможно, вы пропустили подсказку типа в конце кода. Теперь вы можете делать def foo(arg: FooAndBar): .... Средства проверки типов должны иметь возможность информировать вас, когда вы передаете аргумент без требуемых методов.

timgeb 04.09.2018 10:32

Между прочим, ответ - небольшой хардкод, что нормально, если предположить, что существует всего несколько подходящих методов. Если вы хотите продолжить абстрагирование, вы можете написать себе функцию, которая принимает список имен методов и динамически создает ABC с указанными методами и соответствующим подклассом.

timgeb 04.09.2018 10:40
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
8
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это немного бессмысленно для __gt__ и __eq__, потому что object имеет эти атрибуты.

@timgeb: Didn't think of that to be honest, good point. The question is really about documenting this type of duck-typing, so let's pretend that's not the case? :)

В общем случае, я полагаю, вы можете написать себе ABC, который реализует __subclasshook__, а затем напечатать этот класс.

from abc import ABCMeta, abstractmethod

class FooAndBar(metaclass=ABCMeta):
     @abstractmethod
     def foo(self):
         raise NotImplementedError

     @abstractmethod
     def bar(self):
         raise NotImplementedError

     @classmethod
     def __subclasshook__(cls, C):
         if cls is FooAndBar:
             has_foo = any('foo' in X.__dict__ for X in C.__mro__)
             has_bar = any('bar' in X.__dict__ for X in C.__mro__)
             if has_foo and has_bar:
                 return True
         return NotImplemented

class Foo:
    def foo(self):
        pass

class FooBar:
    def foo(self):
        pass

    def bar(self):
        pass

print(isinstance(Foo(), FooAndBar)) # False
print(issubclass(Foo, FooAndBar)) # False
print(isinstance(FooBar(), FooAndBar)) # True
print(issubclass(FooBar, FooAndBar)) # True

def func(arg: FooAndBar):
    pass

Обратите внимание, что определение foo и bar в FooAndBar не требуется для вашей конкретной цели (в любом случае срабатывает крючок подкласса), но пропуск методов выглядел бы очень странно для меня и, вероятно, любого читателя кода.

Другие вопросы по теме