클래스에 메소드를 정의할 때 제일 앞에 self를 적어줘야하며 그 self에는 클래스의 인스턴스가 바인딩된다
그렇다면 언제 어떤 과정을 거쳐 바인딩이 되는 것인가
------------------------------------------------------------
class A:
def say(self):
print("Hello!")
a = A()
a.say() # Hello!
위처럼 평범하게 클래스에 메소드를 정의하고 인스턴스를 생성하여 인스턴스에서 메소드를 호출하면 별다른 이상 없이 메소드가 실행되는 것을 알 수 있다
------------------------------------------------------------
# A.say() # TypeError: say() missing 1 required positional argument: 'self'
그런데 인스턴스가 아닌 클래스에서 직접 메소드를 호출하면 위처럼 에러가 난다
에러를 읽어보면 self에 인스턴스를 바인딩시켜주는 작업이 일어나지 않은 것을 알 수 있다
즉 이 작업은 인스턴스 차원에서 일어난다
------------------------------------------------------------
print(a.say) # <bound method A.say of <__main__.A object at 0x107700048>>
인스턴스의 say attribute를 출력해보면 A object(즉, a)에 A.say의 바운드 메소드라고 나온다
결국 클래스에서 메소드를 정의하면 인스턴스에 이 메소드에 대한 바운드 메소드가 생성되며
이 바운드 메소드는 원래의 메소드의 첫번째 인자에 바운드 메소드를 호출한 객체를 바인딩시켜주는 역할을 한다
------------------------------------------------------------
A.say_twice = lambda self: print("Hello! Hello!")
a.say_twice() # Hello! Hello!
# A.say_twice() # TypeError: <lambda>() missing 1 required positional argument: 'self'
클래스 정의시 뿐만 아니라 정의 후 멍키패칭을 해도 마찬가지로 적용되는 것을 알 수 있다
그렇다면 여기서 딴 생각을 품고 객체에 멍키패칭을 시도해보자
------------------------------------------------------------
a.say_thrice = lambda self: print("Hello! Hello! Hello!")
# a.say_thrice() # TypeError: <lambda>() missing 1 required positional argument: 'self'
print(a.say_thrice) # <function <lambda> at 0x10637af28>
당연하게도 메소드 내에 self 자리를 넣어주면 거기에 자동으로 인스턴스를 바인딩해주는 일은 일어나지 않는다
사실 메소드가 아닌 그저 함수이기 때문에 함수 호출시 처음으로 넣은 인자가 그대로 self에 바인딩될 뿐이다
그렇다면 객체에 메소드를 직접 넣어주고 싶으면서 마치 클래스에 정의된 메소드처럼 self에 인스턴스를 자동으로 바인딩해주고 싶다면 어떻게 해야하는가
------------------------------------------------------------
from types import MethodType
def yes(self):
print("Yes!")
a.yes = MethodType(yes, a)
a.yes() # Yes!
#A.yes() # AttributeError: type object 'A' has no attribute 'yes'
types.MethodType을 이용하면 된다
첫번째 인자로 넣은 yes 함수의 바운드 메소드를 두번째 인자로 넣은 a에 넣어준다
(물론 A클래스 자체는 전혀 변화가 없다
굳이 a.__class__를 따라가 이쪽도 해결해주는 일을 하지는 않는다)
평상시 클래스에 정의하는 메소드의 바운드 메소드가 객체에 넣어지는 과정도 이와 유사할 것이다
------------------------------------------------------------
물론 이런 일을 하지 않는게 좋다
바운드 메소드의 역할과 생성 과정을 이해하는 예시로나 적절하다
파이썬 쿡북에 이를 이용해서 클래스에 정의된 메소드에 데코레이터 적용하는게 나오죠
데코레이터를 클래스로 만들면 원래 클래스의 데코레이팅된 결과물이 함수가 아니라서 디스크립터가 작성되지 않기 때문에.. 내부적으로 처리해줘야하는데 이때 쓰입니다
데코레이터를 함수로 만들었다면 그런 고민이 없지만..
2번째 리플의 원래 클래스의 -> 원래 클래스에 정의된 메소드의
개추