Próbuję zrozumieć, co to jest łatanie małp czy łata małp?
Czy to coś w rodzaju przeciążenia metod / operatorów lub delegowania?
Czy ma coś wspólnego z tymi rzeczami?
Próbuję zrozumieć, co to jest łatanie małp czy łata małp?
Czy to coś w rodzaju przeciążenia metod / operatorów lub delegowania?
Czy ma coś wspólnego z tymi rzeczami?
Odpowiedzi:
Nie, to nie jest żadna z tych rzeczy. Jest to po prostu dynamiczna zamiana atrybutów w czasie wykonywania.
Rozważmy na przykład klasę, która ma metodę get_data
. Ta metoda wykonuje zewnętrzne wyszukiwanie (na przykład w bazie danych lub interfejsie API sieci Web) i wywołują ją różne inne metody w klasie. Jednak w teście jednostkowym nie chcesz polegać na zewnętrznym źródle danych - więc dynamicznie zastępujesz get_data
metodę kodem zwrotnym, który zwraca niektóre ustalone dane.
Ponieważ klasy Pythona są zmienne, a metody są tylko atrybutami klasy, możesz to zrobić tak, jak chcesz - a nawet zastąpić klasy i funkcje w module w dokładnie taki sam sposób.
Ale, jak zauważył komentator , należy zachować ostrożność podczas łączenia małp:
Jeśli oprócz testowych wywołań logicznych coś innego get_data
, wywoła również zastąpione łatką małpy zamiast oryginalnego - co może być dobre lub złe. Tylko uważaj.
Jeśli istnieje jakaś zmienna lub atrybut, który również wskazuje get_data
funkcję do czasu jej zastąpienia, ten alias nie zmieni jej znaczenia i będzie nadal wskazywał na oryginał get_data
. (Dlaczego? Python po prostu ponownie wiąże nazwę get_data
w klasie z jakimś innym obiektem funkcji; nie ma to żadnego wpływu na inne wiązania nazw).
pointing to the original get_data function
? Czy masz na myśli to, że gdy funkcja jest przechowywana w zmiennej, jeśli ktoś ją zmieni, zmienna będzie nadal wskazywać na poprzednią?
get_data
, ponownie przypisujesz nazwę get_data
do fałszywej funkcji. Jeśli jakaś inna nazwa gdzieś w programie jest powiązana z funkcją-dawniej-znana-jako- get_data
, nic się nie zmieni dla tej innej nazwy.
MonkeyPatch to fragment kodu w języku Python, który rozszerza lub modyfikuje inny kod w czasie wykonywania (zwykle podczas uruchamiania).
Prosty przykład wygląda następująco:
from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
return "ook ook eee eee eee!"
SomeClass.speak = speak
Źródło: strona MonkeyPatch na wiki Zope.
Co to jest łatka na małpy?
Mówiąc najprościej, łatanie małp wprowadza zmiany w module lub klasie podczas działania programu.
W dokumentacji Pand znajduje się przykład łatania małp:
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
Aby rozwiązać ten problem, najpierw importujemy nasz moduł:
import pandas as pd
Następnie tworzymy definicję metody, która istnieje niezwiązana i wolna poza zakresem jakichkolwiek definicji klas (ponieważ rozróżnienie między funkcją a niezwiązaną metodą jest dość pozbawione znaczenia, Python 3 eliminuje metodę niezwiązaną):
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]
Następnie po prostu dołączamy tę metodę do klasy, na której chcemy jej użyć:
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
Następnie możemy użyć metody na instancji klasy i usunąć ją, gdy skończymy:
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
Jeśli używasz manglingu nazw (przedrostek atrybutów z podwójnym podkreśleniem, który zmienia nazwę i którego nie polecam), będziesz musiał ręcznie nadać mu nazwę. Ponieważ nie polecam przekłamywania nazwisk, nie będę tego tutaj demonstrować.
Jak możemy wykorzystać tę wiedzę, na przykład podczas testowania?
Powiedzmy, że musimy zasymulować wywołanie pobierania danych do zewnętrznego źródła danych, które powoduje błąd, ponieważ w takim przypadku chcemy zapewnić prawidłowe zachowanie. Możemy małpować łatanie struktury danych, aby zapewnić takie zachowanie. (Więc używając podobnej nazwy metody, jak sugerował Daniel Roseman :)
import datasource
def get_data(self):
'''monkey patch datasource.Structure with this to simulate error'''
raise datasource.DataRetrievalError
datasource.Structure.get_data = get_data
A kiedy przetestujemy to pod kątem zachowania, które opiera się na tej metodzie powodującej błąd, jeśli zostanie poprawnie zaimplementowane, otrzymamy to zachowanie w wynikach testu.
Samo wykonanie powyższych czynności zmieni Structure
obiekt na cały czas trwania procesu, więc będziesz chciał używać ustawień i rozbieżności w swoich najbardziej unikatowych miejscach, aby tego uniknąć, np .:
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
(Chociaż powyższy jest w porządku, będzie to prawdopodobnie lepszy pomysł, aby korzystać z mock
biblioteki załatać kod. mock
„S patch
dekorator byłoby mniej podatne na błędy niż robi to powyżej, który musiałby otrzymać więcej linii kodu, a tym samym większe możliwości wprowadzenia błędów Muszę jeszcze przejrzeć kod, mock
ale wyobrażam sobie, że używa łatania małp w podobny sposób.)
Według Wikipedii :
W Pythonie termin łatka małpa odnosi się tylko do dynamicznych modyfikacji klasy lub modułu w czasie wykonywania, motywowanych intencją łatania istniejącego kodu innej firmy, jako obejście błędu lub funkcji, która nie działa tak, jak chcesz.
Po pierwsze: łatanie małp to zły hack (moim zdaniem).
Często służy do zastępowania metody na poziomie modułu lub klasy niestandardową implementacją.
Najczęstszym przypadkiem użycia jest dodanie obejścia błędu w module lub klasie, gdy nie można zastąpić oryginalnego kodu. W takim przypadku zamieniasz „zły” kod poprzez łatanie małp na implementację wewnątrz własnego modułu / pakietu.
Łatowanie małp można wykonywać tylko w dynamicznych językach, których dobrym przykładem jest Python. Przykładem jest zmiana metody w czasie wykonywania zamiast aktualizacji definicji obiektu; podobnie dodawanie atrybutów (metod lub zmiennych) w czasie wykonywania jest uważane za łatanie małp. Są to często wykonywane podczas pracy z modułami, dla których nie masz źródła, tak że definicji obiektów nie można łatwo zmienić.
Uznaje się to za złe, ponieważ oznacza, że definicja obiektu nie opisuje w pełni ani dokładnie, jak faktycznie się zachowuje.
Patchowanie małp powoduje ponowne otwarcie istniejących klas lub metod w środowisku uruchomieniowym i zmianę zachowania, które należy stosować ostrożnie, lub należy go używać tylko wtedy, gdy jest to naprawdę potrzebne.
Ponieważ Python jest dynamicznym językiem programowania, klasy można modyfikować, dzięki czemu można je ponownie otworzyć i zmodyfikować, a nawet zastąpić.
Co to jest łatanie małp? Patchowanie małp jest techniką używaną do dynamicznej aktualizacji zachowania fragmentu kodu w czasie wykonywania.
Dlaczego warto korzystać z łatania małp? Pozwala nam modyfikować lub rozszerzać zachowanie bibliotek, modułów, klas lub metod w czasie wykonywania bez faktycznej modyfikacji kodu źródłowego
Wniosek Patchowanie małp jest fajną techniką i teraz nauczyliśmy się, jak to robić w Pythonie. Jednak, jak omówiliśmy, ma on swoje wady i należy go używać ostrożnie.
Aby uzyskać więcej informacji, zapoznaj się z [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.