문제

Python3.4를 사용합니다.여기서는 Singledispatch를 사용하여 다른 유형을 전달하고 싶습니다. __mul__ 방법 .코드는 다음과 같습니다.

class Vector(object):

    ## some code not paste  
    @functools.singledispatch
    def __mul__(self, other):
        raise NotImplementedError("can't mul these type")

    @__mul__.register(int)
    @__mul__.register(object)                # Becasue can't use Vector , I have to use object 
    def _(self, other):
        result = Vector(len(self))           # start with vector of zeros
        for j in range(len(self)):
            result[j] = self[j]*other
        return result

    @__mul__.register(Vector)                # how can I use the self't type
    @__mul__.register(object)                # 
    def _(self, other):
        pass # need impl 

코드에서 볼 수 있듯이 지원을 원합니다. Vector*Vertor , 이름 오류가 있습니다.

Traceback (most recent call last):
  File "p_algorithms\vector.py", line 6, in <module>
    class Vector(object):
  File "p_algorithms\vector.py", line 84, in Vector
    @__mul__.register(Vector)                   # how can I use the self't type
NameError: name 'Vector' is not defined

질문은 클래스 메소드에서 클래스 이름과 Type을 어떻게 사용할 수 있습니까?나는 C++에 글꼴 클래스 문이 있다는 것을 알고 있습니다.파이썬이 내 문제를 어떻게 해결합니까?그리고 보니 이상하네요 result = Vector(len(self)) 어디에 Vector 메서드 본문에서 사용할 수 있습니다.


살펴 본 후 http://lukasz.langa.pl/8/single-dispatch-generic-functions/구현하려면 다음 방법을 선택할 수 있습니다.

import unittest
from functools import  singledispatch

class Vector(object):
    """Represent a vector in a multidimensional space."""

    def __init__(self, d):
        self._coords = [0 for i in range(0, d)]
        self.__init__mul__()


    def __init__mul__(self):
        __mul__registry = self.__mul__.registry
        self.__mul__ = singledispatch(__mul__registry[object])
        self.__mul__.register(int, self.mul_int)
        self.__mul__.register(Vector, self.mul_Vector)

    def __setitem__(self, key, value):
        self._coords[key] = value

    def __getitem__(self, item):
        return self._coords[item]

    def __len__(self):
        return len(self._coords)

    def __str__(self):
        return str(self._coords)

    @singledispatch
    def __mul__(self, other):
        print ("error type is ", type(other))
        print (type(other))
        raise NotImplementedError("can't mul these type")

    def mul_int(self,other):
         print ("other type is ", type(other))
         result = Vector(len(self))           # start with vector of zeros
         for j in range(len(self)):
             result[j] = self[j]*other
         return result

    def mul_Vector(self, other):
        print ("other type is ", type(other))
        #result = Vector(len(self))           # start with vector of zeros
        sum = 0
        for i in range(0,len(self)):
            sum += self._coords[i] * other._coords[i]
        return sum

class TestCase(unittest.TestCase):
    def test_singledispatch(self):
        # the following demonstrates usage of a few methods
        v = Vector(5)              # construct five-dimensional <0, 0, 0, 0, 0>
        for i in range(1,6):
            v[i-1] = i
        print(v.__mul__(3))
        print(v.__mul__(v))
        print(v*3)

if __name__ == "__main__":
    unittest.main()

대답이 이상합니다.

other type is  <class 'int'>
[3, 6, 9, 12, 15]
other type is  <class '__main__.Vector'>
55
error type is  <class 'int'>
Traceback (most recent call last):
  File "p_algorithms\vector.py", line 164, in <module>
    print(v*3)
  File "C:\Python34\lib\functools.py", line 710, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "p_algorithms\vector.py", line 111, in __mul__
    raise NotImplementedError("can't mul these type")

v.__mul__(3) 일할 수 있지만 v*3 일할 수 없습니다.이건 이상해요 내 선택에 따르면 v*3 그냥 똑같아 v.__mul__(3) .


@Martijn Pieters의 의견 이후 업데이트되었지만 여전히 구현하고 싶습니다. v*3 클래스.그래서 나는 이것을 시도한다

import unittest
from functools import  singledispatch

class Vector(object):

    @staticmethod
    def static_mul_int(self,other):
         print ("other type is ", type(other))
         result = Vector(len(self))           # start with vector of zeros
         for j in range(len(self)):
             result[j] = self[j]*other
         return result

    @singledispatch
    @staticmethod
    def __static_mul__(cls, other):
        print ("error type is ", type(other))
        print (type(other))
        raise NotImplementedError("can't mul these type")


    __mul__registry2 = __static_mul__.registry
    __mul__ = singledispatch(__mul__registry2[object])
    __mul__.register(int, static_mul_int)

    def __init__(self, d):
        self._coords = [0 for i in range(0, d)]
        self.__init__mul__()


    def __init__mul__(self):
        __mul__registry = self.__mul__.registry
        print ("__mul__registry",__mul__registry,__mul__registry[object])
        self.__mul__ = singledispatch(__mul__registry[object])
        self.__mul__.register(int, self.mul_int)
        print ("at last __mul__registry",self.__mul__.registry)

    # @singledispatch
    # def __mul__(self, other):
    #     print ("error type is ", type(other))
    #     print (type(other))
    #     raise NotImplementedError("can't mul these type")


    def mul_int(self,other):
         print ("other type is ", type(other))
         result = Vector(len(self))           # start with vector of zeros
         for j in range(len(self)):
             result[j] = self[j]*other
         return result

    def __setitem__(self, key, value):
        self._coords[key] = value

    def __getitem__(self, item):
        return self._coords[item]

    def __len__(self):
        return len(self._coords)

    def __str__(self):
        return str(self._coords)


class TestCase(unittest.TestCase):
    def test_singledispatch(self):
        # the following demonstrates usage of a few methods
        v = Vector(5)              # construct five-dimensional <0, 0, 0, 0, 0>
        for i in range(1,6):
            v[i-1] = i
        print(v.__mul__(3))
        print("type(v).__mul__'s registry:",type(v).__mul__.registry)
        type(v).__mul__(v, 3)
        print(v*3)

if __name__ == "__main__":
    unittest.main() 

이 시간 . v.__mul__(3) 오류가 있습니다:

Traceback (most recent call last):
  File "test.py", line 73, in test_singledispatch
    type(v).__mul__(v, 3)
  File "/usr/lib/python3.4/functools.py", line 708, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
TypeError: 'staticmethod' object is not callable

나에게 있어 정적 메소드는 인스턴스 메소드처럼 작동해야 합니다.

도움이 되었습니까?

해결책

당신은 사용할 수 없습니다 functools.singledispatch 방법에 조금도, 적어도 데코레이터로는 아닙니다.Python 3.8에는 메서드에 대해서만 새로운 옵션이 추가되었습니다. functools.singledispatchmethod().

그건 중요하지 않아 Vector 여기에는 아직 정의되지 않았습니다.모든 메소드에 대한 첫 번째 인수는 항상 self, 단일 디스패치를 ​​사용하는 동안 두 번째 인수 여기.

데코레이터가 다음에 적용되기 때문에 함수 객체 클래스 객체가 생성되기 전에 대신 '메서드'를 함수로 등록할 수도 있습니다. 밖의 클래스 본문에 액세스할 수 있습니다. Vector 이름:

class Vector(object):

    @functools.singledispatch
    def __mul__(self, other):
        return NotImplemented

@Vector.__mul__.register(int)
@Vector.__mul__.register(Vector)                
def _(self, other):
    result = Vector(len(self))           # start with vector of zeros
    for j in range(len(self)):
        result[j] = self[j]*other
    return result

지원되지 않는 유형의 경우 NotImplemented 하나씩 일어나는 것, 예외를 발생시키지 않습니다.이런 식으로 Python은 역연산도 시도합니다.

그러나 파견이 핵심이 될 것이기 때문에 잘못된 주장 (self) 어쨌든 여기서는 자신만의 단일 디스패치 메커니즘을 생각해 내야 합니다.

정말로 사용하고 싶다면 @functools.singledispatch 인수를 사용하여 일반 함수에 위임해야 합니다. 반전:

@functools.singledispatch
def _vector_mul(other, self):
    return NotImplemented

class Vector(object):
    def __mul__(self, other):
        return _vector_mul(other, self)


@_vector_mul.register(int)
def _vector_int_mul(other, self):
    result = Vector(len(self))
    for j in range(len(self)):
        result[j] = self[j] * other
    return result

다음을 사용하여 업데이트하는 경우 __init__mul__: v * 3 ~이다 ~ 아니다 다음으로 번역됨 v.__mul__(3).대신 다음과 같이 번역됩니다. type(v).__mul__(v, 3), 보다 특수 메소드 조회 Python 데이터 모델 참조에서.이것 언제나 인스턴스에 직접 설정된 모든 메서드를 우회합니다.

여기 type(v) ~이다 Vector;파이썬은 다음을 찾습니다. 기능, 여기서는 바인딩된 메서드를 사용하지 않습니다.또 왜냐하면 functools.singledispatch 에 파견 첫 번째 인수는 항상 단일 디스패치를 ​​메서드에 직접 사용할 수 없습니다. Vector, 그 첫 번째 인수는 항상 Vector 사례.

즉, 파이썬은 ~ 아니다 설정한 방법을 사용하세요. self ~에 __init__mul__;특별한 방법은 절대 인스턴스를 찾아보았습니다. 특수 메소드 조회 데이터 모델 문서에서.

그만큼 functools.singledispatchmethod() Python 3.8이 추가하는 옵션은 수업 구현하는 데코레이터로서 설명자 프로토콜, 메서드와 마찬가지로.그러면 발송을 처리할 수 있습니다. ~ 전에 바인딩(그래서 이전에 self 인수 목록 앞에 추가됨) 그런 다음 등록된 함수를 바인딩합니다. singledispatch 디스패처가 돌아옵니다.그만큼 이 구현의 소스 코드 이전 Python 버전과 완벽하게 호환되므로 대신 사용할 수 있습니다.

from functools import singledispatch, update_wrapper

# Python 3.8 singledispatchmethod, backported
class singledispatchmethod:
    """Single-dispatch generic method descriptor.

    Supports wrapping existing descriptors and handles non-descriptor
    callables as instance methods.
    """

    def __init__(self, func):
        if not callable(func) and not hasattr(func, "__get__"):
            raise TypeError(f"{func!r} is not callable or a descriptor")

        self.dispatcher = singledispatch(func)
        self.func = func

    def register(self, cls, method=None):
        """generic_method.register(cls, func) -> func

        Registers a new implementation for the given *cls* on a *generic_method*.
        """
        return self.dispatcher.register(cls, func=method)

    def __get__(self, obj, cls):
        def _method(*args, **kwargs):
            method = self.dispatcher.dispatch(args[0].__class__)
            return method.__get__(obj, cls)(*args, **kwargs)

        _method.__isabstractmethod__ = self.__isabstractmethod__
        _method.register = self.register
        update_wrapper(_method, self.func)
        return _method

    @property
    def __isabstractmethod__(self):
        return getattr(self.func, '__isabstractmethod__', False)

그리고 그것을 당신의 Vector() 수업.아직 등록을 하셔야 합니다. Vector 단일 디스패치를 ​​위한 구현 ~ 후에 클래스가 생성된 것입니다. 그래야만 클래스에 대한 디스패치를 ​​등록할 수 있기 때문입니다.

class Vector(object):
    def __init__(self, d):
        self._coords = [0] * d

    def __setitem__(self, key, value):
        self._coords[key] = value

    def __getitem__(self, item):
        return self._coords[item]

    def __len__(self):
        return len(self._coords)

    def __repr__(self):
        return f"Vector({self._coords!r})"

    def __str__(self):
        return str(self._coords)

    @singledispatchmethod
    def __mul__(self, other):
        return NotImplemented

    @__mul__.register
    def _int_mul(self, other: int):
        result = Vector(len(self))
        for j in range(len(self)):
            result[j] = self[j] * other
        return result

@Vector.__mul__.register
def _vector_mul(self, other: Vector):
    return sum(sc * oc for sc, oc in zip(self._coords, other._coords))

물론 먼저 하위 클래스를 만들고 이를 기반으로 파견할 수도 있습니다. 파견은 하위 클래스에서도 작동하기 때문입니다.

class _Vector(object):
    def __init__(self, d):
        self._coords = [0] * d

class Vector(_Vector):
    def __setitem__(self, key, value):
        self._coords[key] = value

    def __getitem__(self, item):
        return self._coords[item]

    def __len__(self):
        return len(self._coords)

    def __repr__(self):
        return f"{type(self).__name__}({self._coords!r})"

    def __str__(self):
        return str(self._coords)

    @singledispatchmethod
    def __mul__(self, other):
        return NotImplemented

    @__mul__.register
    def _int_mul(self, other: int):
        result = Vector(len(self))
        for j in range(len(self)):
            result[j] = self[j] * other
        return result

    @__mul__.register
    def _vector_mul(self, other: _Vector):
        return sum(sc * oc for sc, oc in zip(self._coords, other._coords))

다른 팁

구현 바인딩을 연기해야 ​​하기 때문에 이는 약간 보기 흉합니다. Vector/Vector 이후까지의 곱셈 Vector 실제로 정의되어 있습니다.그러나 단일 디스패치 함수의 첫 번째 인수는 임의 유형이어야 한다는 아이디어가 있습니다. Vector.__mul__ 해당 함수를 호출합니다. self 두 번째 인수로.

import functools

class Vector:

    def __mul__(self, other):
        # Python has already dispatched Vector() * object() here, so
        # swap the arguments so that our single-dispatch works. Note
        # that in general if a*b != b*a, then the _mul_by_other
        # implementations need to compensate.
        return Vector._mul_by_other(other, self)

    @functools.singledispatch
    def _mul_by_other(x, y):
        raise NotImplementedError("Can't multiply vector by {}".format(type(x)))

    @_mul_by_other.register(int)
    def _(x, y):
        print("Multiply vector by int")

@Vector._mul_by_other.register(Vector)
def _(x, y):
    print("Multiply vector by another vector")

x = Vector()
y = Vector()
x * 3
x * y
try:
    x * "foo"
except NotImplementedError:
    print("Caught attempt to multiply by string")
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top