#python
Вопрос:
Новичок в Python здесь — из Perl, так что помилуйте, если я спрашиваю о вещах, связанных с perl.
Я пытаюсь расширить функциональность существующего класса Python (svgpathtools) с помощью дополнительного модуля.
Другими словами, я хотел бы иметь где-нибудь в одном файле (он же модуль, предоставляющий расширение):
def foo(path_a, path_b):
d=0
for t in range(0, 101, 1):
d = d complex_distance(path_a.point(t / 100), path_b.point(t / 100))
return d / 100
setattr(svgpathtools.Path, 'foo', foo)
а затем в файле, использующем расширение
уметь делать что-то подобное:
import svgpathtools.foo
some_path.foo(some_other_path)
Я хотел бы знать:
- как назвать/где сохранить файл, расширяющий модуль svpathtools (т. Е.: каково соответствие между именем модуля и именем файла)
- как это должно выглядеть, чтобы исправить методы svgtools
Моя самая большая проблема — выяснить, как называются подобные вещи, чтобы я мог самостоятельно гуглить. Полные объяснения приветствуются, но указателей для дальнейших исследований мне достаточно, чтобы приступить к работе.
Комментарии:
1. Почему бы не использовать обычное наследование?
2. Не волнуйтесь, для детоксикации от Perl требуется время. 🙂
3. Я не уверен, что исправление ошибок вне тестов уместно. IMHO Лучше наследовать от базового класса или просто объявить эту функцию как автономную и вызвать ее напрямую, без ссылки на svgpathtools. setattr при импорте не является… явным для конечного пользователя, если вам все еще нужно исправить, пожалуйста, оберните его в какую-нибудь
install
функцию4. Более серьезно, у Perl и Python очень разные представления о том, как реализуются классы. В Perl класс-это просто пакет. В Python класс сильно отличается от модуля (а пакет-это просто модуль, содержащий другие модули).
svgpathtools
сам по себе это вовсе не класс; это модуль.svgtools.Path
является атрибутом этого модуля, значением которого является класс. Хотя вы можете добавить новый метод в существующий класс, более вероятно, что вы захотите использовать наследование или композицию для определения нового класса, который будет использоваться вместо него.5. Насколько я помню, Perl даже не поддерживает наследование в языке; существует отдельная библиотека для определения отношения наследования между двумя пакетами. Perl 6 / Raku, возможно, изменил бы это, но у меня никогда не было необходимости (или большого желания) изучать этот язык.
Ответ №1:
В Python метод-это просто атрибут класса, который оказывается функцией, имеющей объект (по соглашению называемый self
) в качестве своего первого аргумента. А класс-это просто объект. Поэтому исправление класса для добавления новых методов или замены существующих (это называется исправлением обезьяны) является тривиальным. Но наследование-гораздо более чистый способ получить тот же результат: новое поведение инкапсулируется в отдельный класс с отдельным именем, что может избавить от дальнейших проблем с обслуживанием…
Вот тривиальный пример с базовым классом, который может вычислить двойное его исходное значение, и расширением, которое может вычислить четверку (* 4):
class A:
def __init__(self, a):
self._val = a
def double(self):
return 2 * self._val
Пример использования:
>>> a = A(2)
>>> a.double()
4
Давайте выведем его:
class B(A):
def quad(self):
return 4 * self._val
которые можно использовать таким образом:
>>> b = B(2)
>>> b.double()
4
>>> b.quad()
8
Вот исправленная версия обезьяны:
>>> A.quad = lambda self: 4 * self._val
что также дает
>>> a = A(2)
>>> a.quad()
8
Но этот способ глобально изменил A
класс, который больше не уважает свой исходный (и, надеюсь, документированный API). Если это не будет прокомментировано красным мигающим шрифтом, будущий мастер, безусловно, обвинит вас в этом…
Тем не менее, исправление обезьян может иметь смысл для исправления ошибки в модуле, которую вы не можете (или не хотите) исправлять на уровне исходного кода…
Комментарии:
1. Спасибо — я упускаю одну деталь: где (т. Е. в каком файле) должно произойти исправление mokey, чтобы его можно было использовать повторно (через
import
)2. Если вы хотите, чтобы он был импортирован стандартным способом, вам действительно следует рассмотреть наследование. Вы можете исправить класс только после загрузки модуля, в котором он объявлен. И поскольку патч является глобальным, вы должны быть осторожны с побочными эффектами в других модулях, использующих тот же класс…