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


547

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

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

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


Google의 정의가 유용하고 가장 일반적이라고 생각합니다.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.
Charlie Parker

답변:


522

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

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

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

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

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

  2. get_data대체 할 때 까지 함수를 가리키는 일부 변수 또는 속성이 존재하는 경우이 별명은 의미를 변경하지 않으며 원래를 계속 가리 킵니다 get_data. (왜 파이썬은 get_data클래스 의 이름 을 다른 함수 객체에 리 바인딩합니다. 다른 이름 바인딩은 전혀 영향을받지 않습니다.)


1
@LutzPrechelt 단지 나를 위해 명확하게 무엇을 의미 pointing to the original get_data function합니까? 누군가가 그 기능을 변경하면 변수가 기존 변수를 계속 가리키면 변수 안에 함수를 저장한다는 의미입니까?
fabriciorissetto

3
@ fabriciorissetto : 일반적으로 파이썬에서 함수 객체를 변경하지 않습니다. monkey-patch get_data하면 이름 get_data을 모의 함수로 리 바인드합니다 . 프로그램의 다른 곳에서 다른 이름이 function-formerly-known-as-에 바인딩 된 get_data경우 해당 다른 이름에 대해서는 아무 것도 변경되지 않습니다.
Lutz Prechelt

1
@LutzPrechelt 이것에 대해 좀 더 설명해 주시겠습니까?
Calvin Ku

원숭이 패치는 디버깅과 데코레이터 또는 객체 팩토리 기능에 특히 유용 할 수 있다고 생각합니다. 그러나 명시적인 것이 암시적인 것보다 낫다는 것을 기억하십시오. 따라서 코드가 문맥에 영향을받지 않도록하고 "유해한 것으로 간주되는 Goto"등을 읽으십시오.
aoeu256

따라서 런타임에 새 코드를 삽입 할 수있는 'eval'기능을 사용하는 것과 비슷한 것입니까?
wintermute

363

MonkeyPatch는 런타임에 (일반적으로 시작시) 다른 코드를 확장하거나 수정하는 Python 코드 조각입니다.

간단한 예는 다음과 같습니다.

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
    return "ook ook eee eee eee!"

SomeClass.speak = speak

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


126

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

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

사용 예

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비슷한 방식으로 원숭이 패치를 사용한다고 상상합니다.)


따라서 monkeypatcher가 실제 방법에 대한 참조를 저장해야하는 부담이 있습니까? 예를 들어, "포인터 유지"단계를 잊어 버리면 어떻게됩니까?
Tommy

3
@Tommy "덮어 쓰기 된"방법으로 회귀하면 0이됩니다. 가비지 수집되어 프로세스 수명 동안 "손실"됩니다.
Aaron Hall

33

Wikipedia 에 따르면 :

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


16

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

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

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


8
일부 모듈이 같은 것을 원숭이 패치하는 경우 : 당신은 운명입니다.
Andreas Jung

49
그것의 힘은 일반적으로 위험 할 수 있지만, 테스트하기에 좋습니다
dkrikun

1
가장 일반적인 사용 사례는 실제로 테스트, 특히 단위 테스트입니다. 코드 만 테스트하기를 원하므로 외부 호출을 패치하여 예상 결과를 반환하십시오.
brocoli

1
그것은 악의가 아닙니다. 포크를 사용하여 새로운 의존성을 만들지 않고 새로운 릴리스가 나올 때까지 다른 사람들의 소프트웨어에서 버그를 패치하는 데 사용합니다.
nurettin

1
몽키 패치는 수정이 아닌 클래스 / 메소드의 새로운 패치 버전을 반환하는 데코레이터 내부에서만 패치를 수행함으로써 변경 가능하고 "문맥에 민감한"방식이 아닌 "순수한 기능 방식"으로 수행 할 수 있습니다. 많은 C # / Java 프로그래머는 REPL 기반 개발에 대해 알지 못하므로 모든 것을 정적으로 정의해야하는 IDE에서 코딩합니다. C # / Java에는 원숭이 패치가 없으므로 JavaScript, Smalltalk, Lisp, Python 등에서 정적 IDE 기반 개발 관행에 위배되는 것처럼 악의적 인 것으로 가정합니다.
aoeu256

13

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

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


그러나 원숭이 패치는 기존 객체 나 클래스를 수정하는 대신 데코레이터 내부의 멤버에 패치 된 새 버전의 객체를 만들어 "이미 패치하려고합니다"라는 비명을 지 릅니다.
aoeu256

패치 된 멤버에 주석을 사용하여 데코레이터가 패치에서 패치하는 데 사용 된 패치 된 멤버에 저장할 수 있습니다. 실행 취소 메소드를 사용하여 실행 취소 가능한 새 버전의 함수 객체를 작성하는 실행 취소 가능한 데코레이터가 있다고 가정 해 봅시다. 데코레이터에는 취소 할 수없는 데코레이터를 가리키는 패처 필드를 넣을 수 있습니다.
aoeu256

5

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

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


1

원숭이 패치 란 무엇입니까? 원숭이 패치는 런타임에 코드 조각의 동작을 동적으로 업데이트하는 데 사용되는 기술입니다.

원숭이 패치를 사용하는 이유는 무엇입니까? 실제로 소스 코드를 수정하지 않고도 런타임에 라이브러리, 모듈, 클래스 또는 메소드의 동작을 수정하거나 확장 할 수 있습니다.

결론 Monkey patching은 멋진 기술이며 이제 파이썬에서 그 방법을 배웠습니다. 그러나 우리가 논의했듯이, 그것은 그 자체의 단점이 있으며 신중하게 사용해야합니다.

자세한 내용은 다음을 참조하십시오 [1] : https://medium.com/@nagillavenkatesh1234/monkey-patching-in-python-explained-with-examples-25eed0aea505

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.