Использование дизайна по контракту в Python - PullRequest
40 голосов
/ 19 декабря 2011

Я хочу начать использовать DBC в большом количестве проектов на основе Python на работе и мне интересно, какой опыт другие испытали с ним. Пока что мое исследование показало следующее:

  • http://www.python.org/dev/peps/pep-0316/ - PEP 316, который должен стандартизировать проект по контракту для Python, который был отложен. Этот ПКП предлагает использовать строки документации.
  • http://www.wayforward.net/pycontract/ - Контракты для Python. Кажется, что это полный, но не поддерживаемый фреймворк, использующий строки документации.
  • http://www.nongnu.org/pydbc/ - PyDBC, который реализует контракты с использованием метаклассов. Также не поддерживается в течение нескольких лет.

Мои вопросы: использовали ли вы DBC с Python для зрелого производственного кода? Насколько хорошо это работает / стоило ли усилий? Какие инструменты вы бы порекомендовали?

Ответы [ 5 ]

17 голосов
/ 22 января 2012

PEP, который вы обнаружили, еще не принят, поэтому нет стандартного или принятого способа сделать это (пока - вы всегда можете реализовать PEP самостоятельно!).Однако, как вы обнаружили, есть несколько разных подходов.

Вероятно, самый легкий - просто использовать декораторы Python.В Python Decorator Library есть набор декораторов для предварительных / постусловий, которые довольно просты в использовании.Вот пример с этой страницы:

  >>> def in_ge20(inval):
  ...    assert inval >= 20, 'Input value < 20'
  ...
  >>> def out_lt30(retval, inval):
  ...    assert retval < 30, 'Return value >= 30'
  ...
  >>> @precondition(in_ge20)
  ... @postcondition(out_lt30)
  ... def inc(value):
  ...   return value + 1
  ...
  >>> inc(5)
  Traceback (most recent call last):
    ...
  AssertionError: Input value < 20

Теперь вы упоминаете инварианты классов.Это немного сложнее, но я бы выбрал способ определения вызываемого объекта для проверки инварианта, а затем в конце каждого вызова метода что-то вроде проверки декоратора после условия.В качестве первого варианта вы, вероятно, можете просто использовать декоратор постусловия как есть.

11 голосов
/ 10 августа 2013

По моему опыту стоит заниматься дизайном по контракту даже без языковой поддержки.Для методов, которые не являются переопределенными утверждениями, вместе со строкой документации достаточно как предварительных, так и постусловий.Для переопределенных методов мы разделяем метод на два: открытый метод, который проверяет предварительные и постусловия, и защищенный метод, который обеспечивает реализацию и может быть переопределен подклассами.Вот пример последнего:

class Math:
    def square_root(self, number)
        """
        Calculate the square-root of C{number}

        @precondition: C{number >= 0}

        @postcondition: C{abs(result * result - number) < 0.01}
        """
        assert number >= 0
        result = self._square_root(number)
        assert abs(result * result - number) < 0.01
        return result

    def _square_root(self, number):
        """
        Abstract method for implementing L{square_root()}
        """
        raise NotImplementedError()

Я получил квадратный корень в качестве общего примера разработки по контракту из эпизода о разработке по контракту на радиоинженерии программного обеспечения (http://www.se -radio.net / 2007/03 / эпизод-51-дизайн по-контракта / ).Они также упомянули о необходимости языковой поддержки, потому что утверждения не помогли в обеспечении принципа подстановки Лискова, хотя мой пример выше демонстрирует обратное.Я должен также упомянуть идиому C ++ pimpl (частная реализация) в качестве источника вдохновения, хотя это имеет совершенно иное назначение.

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

Лучшая поддержка инструментов может предложить нам еще больше возможностей в будущем, я приветствую это.

7 голосов
/ 19 декабря 2011

Я не использовал дизайн по контракту в python, поэтому не могу ответить на все ваши вопросы.Однако я потратил некоторое время на просмотр библиотеки контрактов , последняя версия которой была недавно выпущена, и она выглядит довольно красиво.

В было обсуждение некоторых библиотекReddit .

5 голосов
/ 13 августа 2018

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

Поэтому мы разработали icontract . Сообщения об ошибках автоматически генерируются путем повторного обхода декомпилированного кода функции и оценки всех задействованных значений:

import icontract

>>> class B:
...     def __init__(self) -> None:
...         self.x = 7
...
...     def y(self) -> int:
...         return 2
...
...     def __repr__(self) -> str:
...         return "instance of B"
...
>>> class A:
...     def __init__(self)->None:
...         self.b = B()
...
...     def __repr__(self) -> str:
...         return "instance of A"
...
>>> SOME_GLOBAL_VAR = 13
>>> @icontract.pre(lambda a: a.b.x + a.b.y() > SOME_GLOBAL_VAR)
... def some_func(a: A) -> None:
...     pass
...
>>> an_a = A()
>>> some_func(an_a)
Traceback (most recent call last):
  ...
icontract.ViolationError: 
Precondition violated: (a.b.x + a.b.y()) > SOME_GLOBAL_VAR:
SOME_GLOBAL_VAR was 13
a was instance of A
a.b was instance of B
a.b.x was 7
a.b.y() was 2

Мы нашли библиотеку довольно полезной как в процессе производства (из-за информационных сообщений), так и во время разработки (поскольку она позволяет обнаруживать ошибки на ранних этапах).

5 голосов
/ 24 января 2012

Хотя это не совсем проектирование по контракту , некоторые платформы тестирования предпочитают, чтобы подход к тестированию свойств был очень близок концептуально.

Рандомизированное тестирование на наличие определенных свойств во время выполнения позволяет легко проверить:

  • инварианты
  • домены входных и выходных значений
  • другие предварительные и постусловия

Для Python существует несколько сред тестирования в стиле QuickCheck:

...