2011-05-15 6 views
4

Muhammad Alkarouri 대답에 의해 What are good uses for Python3's "Function Annotations"에서 영감을 얻어이 함수를 사용하려면 multimethod을 사용하고 싶습니다. 나는이데코 레이팅 메서드 (클래스 메서드 오버로드)

registry = {} 

class MultiMethod(object): 
    def __init__(self, name): 
     self.name = name 
     self.typemap = {} 
    def __call__(self, *args): 
     types = tuple(arg.__class__ for arg in args) # a generator expression! 
     function = self.typemap.get(types) 
    if function is None: 
     raise TypeError("no match") 
    return function(*args) 
def register(self, types, function): 
    if types in self.typemap: 
     raise TypeError("duplicate registration") 
    self.typemap[types] = function 

def multimethod(function): 
    name = function.__name__ 
    mm = registry.get(name) 
    if mm is None: 
     mm = registry[name] = MultiMethod(name) 
    types = tuple(function.__annotations__.values()) 
    mm.register(types, function) 
    return mm 

class A: 
@multimethod 
def foo(self, a: int): 
    return "an int" 

a = A() 
print(a.foo(1)) 

을 할 때, 나는이있어 : 때문에 self 인수의, Decorating a method에 설명 된대로, 예상 할 수있는 것 같다

Traceback (most recent call last): 
    File "test.py", line 33, in <module> 
    print(a.foo(1)) 
    File "test.py", line 12, in __call__ 
    return function(*args) 
TypeError: foo() takes exactly 2 arguments (1 given) 

.

하지만 어떻게 작동하게하는지 잘 모릅니다. 글쎄, 내가 "자기"를 제거하면, (거의) 잘 작동하지만, 나는 그것을 제거하고 싶지 않다. 내가 연습을 위해 이것을하고 있다는 것에주의하십시오. 메소드 오버로드를 제공하는 libs가 있다는 것을 알고 있습니다.

내가 시도하는 것 :

  • 매우 어리석은 하지만 원했고 - 추가 매개 변수 selfdef multimethod(function)에 - 동일한 오류

  • 을 내가 class MultiMethod 세 번째 매개 변수의 __init__에 추가하는 방법에 대한 생각 - obj 그리고 회원으로 self 저장되어 있지만이 기능을 통해 multimethod 통해이 작업을 수행 할 수 없습니다.

  • 나는 장식에 대한 매개 변수를 추가하지 않기 때문에이 옵션 (모든 가능한 경우)

내가 몇 가지 비슷한 질문을 읽어 무시되지만, 내가 찾던 찾을 수 없습니다 에 대한. 나는 이것이 가짜 질문이라고 확신하지만, 나는 아이디어가 부족했다.

답변

5

기본 문제는 함수 대신 클래스를 사용한다는 것입니다. 이 클래스가 자동으로 발생하는 함수와는 달리, 클래스를 호출 한 인스턴스에 해당 클래스를 바인딩하는 메커니즘이 없습니다. 당신이 a.foo(..)을 수행 할 때

한마디로

, 그것은 MultiMethod을 반환하지만이 객체가 a에 바인딩되어있을 가능성 아무 생각이 없습니다.

어떤 방법 으로든 인스턴스를 전달해야합니다.

registry = {} 

class MultiMethod(object): 
    def __init__(self, name): 
     self.name = name 
     self.typemap = {} 

    # self = a MultiMethod instance, instance = the object we want to bind to 
    def __call__(self, instance, *args): 
     types = tuple(arg.__class__ for arg in args) # a generator expression! 
     function = self.typemap.get(types) 

     if function is None: 
      raise TypeError("no match") 
     return function(instance, *args) 

    def register(self, types, function): 
     if types in self.typemap: 
      raise TypeError("duplicate registration") 
     self.typemap[types] = function 

def multimethod(function): 
    name = function.__name__ 
    mm = registry.get(name) 
    if mm is None: 
     mm = registry[name] = MultiMethod(name) 

    types = tuple(function.__annotations__.values()) 
    mm.register(types, function) 
    # return a function instead of a object - Python binds this automatically 
    def getter(instance, *args, **kwargs): 
     return mm(instance, *args, **kwargs) 
    return getter 

class A: 
    @multimethod 
    def foo(self, a: int): 
     return "an int", a 

a = A() 
print(a.foo(1)) 

더 복잡한 방법이 바인딩을 수행하는 A 클래스에 자신의 설명을 작성하는 것입니다 : 쉬운 방법 중 하나는 함수에 모든 포장하고 일이 어떻게 파이썬을하도록하는 것입니다.

+0

Haaa, 정말 고맙습니다. +1하고 받아들입니다. –

관련 문제