클래스에 메소드를 정의할 때 제일 앞에 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__를 따라가 이쪽도 해결해주는 일을 하지는 않는다)

평상시 클래스에 정의하는 메소드의 바운드 메소드가 객체에 넣어지는 과정도 이와 유사할 것이다


------------------------------------------------------------


물론 이런 일을 하지 않는게 좋다

바운드 메소드의 역할과 생성 과정을 이해하는 예시로나 적절하다