Я пытаюсь понять, что такое исправление обезьяны или исправление обезьяны?
Это что-то вроде перегрузки или делегирования методов / операторов?
Есть ли что-то общее с этими вещами?
Я пытаюсь понять, что такое исправление обезьяны или исправление обезьяны?
Это что-то вроде перегрузки или делегирования методов / операторов?
Есть ли что-то общее с этими вещами?
Ответы:
Нет, это не похоже ни на одну из этих вещей. Это просто динамическая замена атрибутов во время выполнения.
Например, рассмотрим класс, у которого есть метод get_data
. Этот метод выполняет внешний поиск (например, в базе данных или веб-API), и различные другие методы в классе вызывают его. Однако в модульном тесте вы не хотите зависеть от внешнего источника данных - поэтому вы динамически заменяете get_data
метод заглушкой, которая возвращает некоторые фиксированные данные.
Поскольку классы Python являются изменяемыми, а методы - это просто атрибуты класса, вы можете делать это сколько угодно - и фактически вы можете даже заменить классы и функции в модуле точно таким же образом.
Но, как отметил комментатор , соблюдайте осторожность при установке обезьян:
Если что-то еще, кроме вашей тестовой логики get_data
, также вызовет, это также вызовет замену, исправленную обезьяной, а не оригинал - что может быть хорошим или плохим. Просто будь осторожен.
Если существует некоторая переменная или атрибут, который также указывает на get_data
функцию к моменту ее замены, этот псевдоним не изменит своего значения и будет продолжать указывать на оригинал get_data
. (Почему? Python просто привязывает имя get_data
в вашем классе к другому объекту функции; на другие привязки имен это никак не влияет.)
pointing to the original get_data function
? Вы имеете в виду, когда вы сохраняете функцию внутри переменной, если кто-то изменяет эту функцию, переменная будет продолжать указывать на старую?
get_data
, вы привязываете имя get_data
к фиктивной функции. Если какое-либо другое имя где-либо еще в программе связано с ранее известной функцией-функцией 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 является динамическим языком программирования, классы изменчивы, поэтому вы можете открыть их и изменить или даже заменить.
Что такое исправление обезьян? Исправление обезьян - это метод, используемый для динамического обновления поведения фрагмента кода во время выполнения.
Зачем использовать исправления обезьян? Это позволяет нам изменять или расширять поведение библиотек, модулей, классов или методов во время выполнения без фактического изменения исходного кода.
Заключение Исправление обезьян - это классная техника, и теперь мы научились делать это на Python. Однако, как мы уже говорили, он имеет свои недостатки и должен использоваться осторожно.
Для получения дополнительной информации, пожалуйста, обратитесь [1]: https://medium.com/@nagillavenkatesh1234/monkey-patching-in-python-explained-with-examples-25eed0aea505
Monkey patching is a technique to add, modify, or suppress the default behavior of a piece of code at runtime without changing its original source code.