[python] 원숭이 패치 란 무엇입니까?

원숭이 패치 또는 원숭이 패치 란 무엇입니까?

메서드 / 운영자 오버로드 또는 위임과 같은 것입니까?

이것들과 공통점이 있습니까?



답변

아니요, 그것은 그런 것들과 다릅니다. 단순히 런타임에 속성을 동적으로 대체하는 것입니다.

예를 들어, 메소드가있는 클래스를 고려하십시오 get_data. 이 메소드는 외부 조회 (예 : 데이터베이스 또는 웹 API)를 수행하고 클래스의 다양한 기타 메소드가이를 호출합니다. 그러나 단위 테스트에서는 외부 데이터 소스에 의존하고 싶지 않으므로 get_data고정 된 데이터를 반환하는 스텁으로 메서드 를 동적으로 바꿉니다.

파이썬 클래스는 변경 가능하고 메소드는 클래스의 속성 일 뿐이므로 원하는만큼이 작업을 수행 할 수 있으며 실제로 모듈에서 클래스와 함수를 같은 방식으로 대체 할 수도 있습니다.

그러나 주석가가 지적했듯이 원숭이 패치를 할 때주의하십시오.

  1. 테스트 로직 이외의 다른 항목 get_data도 호출하면 원본보다 원숭이 패치 교체를 호출합니다. 좋거나 나쁠 수 있습니다. 조심하세요.

  2. 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

출처 : Zope 위키의 MonkeyPatch 페이지.


답변

원숭이 패치 란 무엇입니까?

간단히 말해서, 원숭이 패치는 프로그램이 실행되는 동안 모듈이나 클래스를 변경합니다.

사용 예

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

이름 맹 글링에 대한주의 사항

이름 변환 (이중 밑줄이 붙은 접두어로 이름을 변경하고 권장하지 않는 속성)을 사용하는 경우이 작업을 수행하면 수동으로 이름을 바꿔야합니다. 이름 맹 글링을 권장하지 않기 때문에 여기서는 설명하지 않습니다.

테스트 예

예를 들어 테스트에서이 지식을 어떻게 사용할 수 있습니까?

이러한 경우에 올바른 동작을 보장하기 위해 외부 데이터 소스에 대한 데이터 검색 호출을 시뮬레이션해야 오류가 발생한다고 가정하십시오. 이 동작을 보장하기 위해 데이터 구조를 원숭이 패치 할 수 있습니다. (따라서 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

오류를 발생시키는이 방법에 의존하는 동작을 테스트 할 때 올바르게 구현하면 테스트 결과에 해당 동작이 나타납니다.

위의 작업을 수행하면 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‘의 patch데코레이터는 위의 작업보다 오류가 적기 때문에 더 많은 코드 줄이 필요하므로 오류가 발생할 가능성이 더 큽니다. 코드를 아직 검토하지 않았지만 mock비슷한 방식으로 원숭이 패치를 사용한다고 상상합니다.)


답변

Wikipedia 에 따르면 :

파이썬에서 몽키 패치라는 용어는 런타임에 클래스 또는 모듈의 동적 수정만을 의미하며 기존 타사 코드를 버그 또는 기능에 대한 해결 방법으로 패치하여 의도 한대로 작동하지 않도록합니다.


답변

첫째 : 원숭이 패치는 사악한 해킹입니다 (제 생각에는).

모듈 또는 클래스 레벨의 메소드를 사용자 정의 구현으로 바꾸는 데 종종 사용됩니다.

가장 일반적인 사용 사례는 원래 코드를 바꿀 수 없을 때 모듈이나 클래스의 버그에 대한 해결 방법을 추가하는 것입니다. 이 경우 원숭이 패치를 통해 “잘못된”코드를 자체 모듈 / 패키지 내부의 구현으로 바꿉니다.


답변

원숭이 패치는 동적 언어로만 수행 할 수 있으며, 그 중 파이썬이 좋은 예입니다. 객체 정의를 업데이트하는 대신 런타임에 메소드를 변경하는 것이 한 예입니다. 마찬가지로 런타임에 속성 (메소드 또는 변수)을 추가하는 것은 원숭이 패치로 간주됩니다. 이것들은 종종 소스가없는 모듈로 작업 할 때 수행되므로 객체 정의를 쉽게 변경할 수 없습니다.

이것은 객체의 정의가 실제로 어떻게 동작하는지 완전히 또는 정확하게 설명하지 않기 때문에 나쁜 것으로 간주됩니다.


답변

Monkey patching은 런타임에 클래스의 기존 클래스 또는 메소드를 다시 열고 동작을 변경하는 데주의를 기울여야합니다. 그렇지 않으면 실제로 필요할 때만 사용해야합니다.

Python은 동적 프로그래밍 언어이므로 클래스는 변경 가능하므로 클래스를 다시 열고 수정하거나 바꿀 수 있습니다.