Что такое исправление обезьян?
Я пытаюсь понять, что такое исправление обезьяны или исправление обезьяны?
Это что-то вроде перегрузки или делегирования методов / операторов?
Есть ли что-нибудь общее с этими вещами?
7 ответов
Нет, это не похоже ни на одну из этих вещей. Это просто динамическая замена атрибутов во время выполнения.
Например, рассмотрим класс, который имеет метод get_data
, Этот метод выполняет внешний поиск (например, в базе данных или веб-API), и различные другие методы в классе вызывают его. Однако в модульном тесте вы не хотите зависеть от внешнего источника данных - поэтому вы динамически заменяете get_data
метод с заглушкой, которая возвращает некоторые фиксированные данные.
Поскольку классы Python являются изменяемыми, а методы - это просто атрибуты класса, вы можете делать это сколько угодно - и фактически вы можете даже заменить классы и функции в модуле точно таким же образом.
Но, как Lutz Prechelt, соблюдайте осторожность при установке обезьян:
Если что-то еще кроме вашей тестовой логики вызывает
get_data
Кроме того, он также будет называть замену, исправленную обезьяной, а не оригиналом - что может быть хорошим или плохим. Просто будь осторожен.Если существует некоторая переменная или атрибут, это также указывает на
get_data
к тому времени, когда вы замените его, этот псевдоним не изменит своего значения и будет продолжать указывать на исходныйget_data
, (Почему? Python просто перепривязывает имяget_data
в вашем классе к другому объекту функции; другие привязки имен вообще не затрагиваются.)
MonkeyPatch - это фрагмент кода Python, который расширяет или модифицирует другой код во время выполнения (обычно при запуске).
Простой пример выглядит так:
from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
return "ook ook eee eee eee!"
SomeClass.speak = speak
Источник: страница MonkeyPatch на вики Zope.
Что такое патч обезьяны?
Проще говоря, исправление обезьян вносит изменения в модуль или класс во время работы программы.
Пример использования
В документации Pandas есть пример исправления обезьян:
import pandas as pd
def just_foo_cols(self):
"""Get a list of column names containing the string 'foo'
"""
return [x for x in self.columns if 'foo' in x]
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method
Чтобы разбить это, сначала мы импортируем наш модуль:
import pandas as pd
Затем мы создаем определение метода, которое существует несвязанным и свободным вне области определения любого класса (поскольку различие между функцией и несвязанным методом довольно бессмысленно, Python 3 устраняет несвязанный метод):
def just_foo_cols(self):
"""Get a list of column names containing the string 'foo'
"""
return [x for x in self.columns if 'foo' in x]
Затем мы просто присоединяем этот метод к классу, на котором мы хотим его использовать:
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
И тогда мы можем использовать метод в экземпляре класса и удалить метод, когда закончим:
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method
Будьте осторожны
Если вы используете искажение имени (добавление атрибута к имени с двойным подчеркиванием, которое меняет имя, и которое я не рекомендую), вам придется вручную изменять имя, если вы делаете это. Поскольку я не рекомендую искажение имени, я не буду демонстрировать это здесь.
Пример тестирования
Как мы можем использовать эти знания, например, при тестировании?
Скажем, нам нужно смоделировать вызов извлечения данных из внешнего источника данных, который приводит к ошибке, потому что мы хотим обеспечить правильное поведение в таком случае. Мы можем обезопасить структуру данных, чтобы обеспечить такое поведение. (Таким образом, используя аналогичное имя метода, предложенное Даниэлем Роземаном:)
import datasource
def get_data(self):
'''monkey patch datasource.Structure with this to simulate error'''
raise datasource.DataRetrievalError
datasource.Structure.get_data = get_data
И когда мы проверяем его на поведение, которое основано на том, что этот метод вызывает ошибку, если он правильно реализован, мы получим такое поведение в результатах теста.
Просто выполнение вышеизложенного изменит Structure
объект для жизни процесса, так что вы хотите использовать настройки и разрывы в ваших тестах юнитов, чтобы избежать этого, например:
def setUp(self):
# retain a pointer to the actual real method:
self.real_get_data = datasource.Structure.get_data
# monkey patch it:
datasource.Structure.get_data = get_data
def tearDown(self):
# give the real method back to the Structure object:
datasource.Structure.get_data = self.real_get_data
(Хотя все вышесказанное хорошо, вероятно, было бы лучше использовать mock
библиотека для исправления кода. mock
"s patch
Декоратор будет менее подвержен ошибкам, чем при выполнении вышеизложенного, что потребует больше строк кода и, следовательно, больше возможностей для введения ошибок. Я еще не рассмотрел код в mock
но я предполагаю, что он использует патч обезьян аналогичным образом.)
Согласно Википедии:
В Python термин "исправление обезьяны" относится только к динамическим модификациям класса или модуля во время выполнения, мотивированным намерением исправлять существующий сторонний код в качестве обходного пути для ошибки или функции, которая не действует по вашему желанию.
Во-первых: исправление обезьян - злой хак (на мой взгляд).
Он часто используется для замены метода на уровне модуля или класса пользовательской реализацией.
Самым распространенным вариантом использования является добавление обходного пути для ошибки в модуле или классе, когда вы не можете заменить исходный код. В этом случае вы заменяете "неправильный" код с помощью патчей обезьяны реализацией внутри вашего собственного модуля / пакета.
Патч обезьяны может быть сделан только на динамических языках, примером чего является python. Изменение метода во время выполнения вместо обновления определения объекта является одним из примеров, аналогичным образом, добавление атрибутов (методов или переменных) во время выполнения считается исправлением обезьяны. Это часто делается при работе с модулями, для которых у вас нет источника, так что определения объектов не могут быть легко изменены.
Это считается плохим, потому что это означает, что определение объекта не полностью или точно не описывает, как он на самом деле ведет себя.
Исправление обезьян - это повторное открытие существующих классов или методов в классе во время выполнения и изменение поведения, которое следует использовать осторожно, или вы должны использовать его только тогда, когда это действительно необходимо.
Поскольку Python является динамическим языком программирования, классы являются изменяемыми, поэтому вы можете открыть их и изменить или даже заменить.
Что такое патч обезьяны? Исправление обезьяны - это метод, используемый для динамического обновления поведения фрагмента кода во время выполнения.
Зачем использовать исправление обезьяны? Это позволяет нам изменять или расширять поведение библиотек, модулей, классов или методов во время выполнения без фактического изменения исходного кода.
Заключение Установка патчей Monkey - это классная техника, и теперь мы узнали, как это сделать на Python. Однако, как мы уже говорили, у него есть свои недостатки, и его следует использовать осторожно.
Для получения дополнительной информации обратитесь к [1]: https://medium.com/@nagillavenkatesh1234/monkey-patching-in-python-explained-with-examples-25eed0aea505