使用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
,这有名称错误
问题可能是如何在类的方法中使用类名a类型?我知道c++有字体类语句。python如何解决我的问题?奇怪的是,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
和{
在@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
对我来说,静态方法的作用应该类似于实例方法。在
{/strong>至少你不能使用所有的装饰方法。Python3.8添加了一个新的选项,仅用于方法:^{} 。在
这里没有定义
Vector
并不重要;任何方法的第一个参数总是self
,而这里的第二个参数将使用单个分派。在因为decorator在类对象创建之前应用于函数对象,所以您可以将您的“方法”注册为函数,而不是在类主体的外部,这样您就可以访问
Vector
名称:对于不受支持的类型,您需要返回
NotImplemented
singleton,而不是引发异常。这样Python也会尝试逆操作。在但是,由于调度无论如何都要在这里输入错误的参数(
self
),因此您必须想出自己的单一分派机制。在如果你真的想使用
^{pr2}$@functools.singledispatch
,你就必须委托给一个正则函数,并且参数的倒数为:至于使用
__init__mul__
的更新:v * 3
是而不是翻译成v.__mul__(3)
。它被转换为type(v).__mul__(v, 3)
,请参阅Python数据模型参考中的Special method lookup。这个总是绕过直接在实例上设置的任何方法。在这里
type(v)
是Vector
;Python查找函数,它在这里不会使用绑定方法。同样,由于functools.singledispatch
总是在first参数上分派,所以不能直接对Vector
的方法使用单个分派,因为第一个参数总是Vector
实例。在换句话说,Python将使用您在
__init__mul__
中的self
上设置的方法;特殊方法是从不查找实例,请参阅数据模型文档中的Special method lookup。在python3.8添加的
functools.singledispatchmethod()
选项使用类作为实现descriptor protocol的装饰器,就像方法一样。这样,它就可以在绑定之前处理dispatch(因此,在self
之前将被添加到参数列表中),然后绑定singledispatch
调度器返回的注册函数。source code for this implementation与较旧的Python版本完全兼容,因此您可以改用它:并将其应用于您的
Vector()
类。在创建类之后,您仍然需要为单个分派注册您的Vector
实现,因为只有这样才能为类注册分派:当然,您也可以先创建一个子类并在此基础上进行分派,因为分派也适用于子类:
这有点难看,因为您需要将
Vector
/Vector
乘法的实现推迟到实际定义Vector
之后。但其思想是单个分派函数需要第一个参数是任意类型的,因此Vector.__mul__
将用self
作为第二个参数调用该函数。在相关问题 更多 >
编程相关推荐