Куда поместить функцию, которая действует на два экземпляра определенного класса

#python #design-patterns

Вопрос:

Это действительно вопрос дизайна, и я хотел бы немного узнать, какие шаблоны дизайна использовать.

У меня есть модуль, скажем curves.py , который определяет Bezier класс. Затем я хочу написать функцию intersection , которая использует рекурсивный алгоритм для поиска пересечений между двумя экземплярами Bezier .

Какие у меня есть варианты для размещения этих функций? Каковы некоторые лучшие практики в этом случае? В настоящее время я написал функцию в самом модуле (а не как метод для класса).

Так что в настоящее время у меня есть что-то вроде:

 def intersections(inst1, inst2): ...

def Bezier(): ... 

 

и я могу вызвать функцию, передав два экземпляра:

 from curves import Bezier, intersections

a = Bezier()
b = Bezier()

result = intersections(a, b)
 

Однако другим вариантом (который я могу придумать) было бы создание intersection метода класса. В этом случае я бы вместо этого использовал

 a.intersections(b) 
 

Для меня первый выбор имеет немного больше смысла, так как кажется более естественным позвонить intersections(a, b) , чем a.intersections(b) . Однако другой вариант кажется более естественным в том смысле, что функция intersection действительно действует только на Bezier экземпляры, и это кажется более инкапсулированным.

Считаете ли вы, что один из них лучше другого, и в таком случае, по каким причинам? Есть ли здесь какие-либо другие варианты дизайна для использования? Существуют ли какие-либо лучшие практики?

Ответ №1:

В качестве примера вы можете сравнить, как встроенный set класс делает это:

пересечение(*другие)
набор amp; другое amp; …
Возвращает новый набор с элементами, общими для набора и всех остальных.

So intersection определяется как обычный метод экземпляра класса, который принимает другие (или несколько) наборов и возвращает пересечение, и его можно назвать как a.intersection(b) .

Однако из-за стандартной механики работы методов экземпляра вы также можете написать его set.intersection(a, b) по буквам, и на практике вы будете видеть это довольно часто, так как, как вы говорите, это кажется более естественным.

Вы также можете переопределить __and__ метод, чтобы он стал доступен как a amp; b .

С точки зрения простоты использования, размещение его в классе также более удобно, потому что вы можете просто импортировать Bezier класс, и все связанные с ним функции будут доступны автоматически, и их также можно обнаружить с помощью help(Bezier) .

Комментарии:

1. Это звучит как множество веских причин использовать его в таком дизайне.