gpt4 book ai didi

python3 : singledispatch in class, 如何分派(dispatch)自身类型

转载 作者:太空狗 更新时间:2023-10-29 20:14:19 24 4
gpt4 key购买 nike

使用python3.4。在这里我想使用 singledispatch 在 __mul__ 方法中分派(dispatch)不同的类型。像这样的代码:

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++ 有字体类语句。 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*3v.__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,而您在这里对第二个参数使用单分派(dispatch)。

因为装饰器在创建类对象之前应用于函数对象,所以您也可以将您的“方法”注册为函数,而不是在类主体的外部 ,因此您可以访问 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 singleton,而不是引发异常。这样 Python 也会尝试逆运算。

但是,无论如何,由于调度将以错误的参数(self)为关键,因此您必须想出自己的单一调度机制。

如果你真的想使用@functools.singledispatch,你必须委托(delegate)给一个常规函数,参数反转:

@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),参见 Special method lookup在 Python 数据模型引用中。这总是绕过直接在实例上设置的任何方法。

这里的type(v)Vector; Python 查找函数,它不会在这里使用绑定(bind)方法。同样,因为 functools.singledispatchfirst 参数上进行分派(dispatch),所以总是不能在 Vector 的方法上直接使用单分派(dispatch),因为那是第一个参数始终是 Vector 实例。

换句话说,Python 将不会使用您在__init__mul__ 中为self 设置的方法;特殊方法从不在实例上查找,参见Special method lookup在数据模型文档中。

Python 3.8 添加的functools.singledispatchmethod() 选项使用 作为实现descriptor protocol 的装饰器。 ,就像方法一样。这让它可以在 before 绑定(bind)之前处理调度(因此 before self 将被添加到参数列表中)然后绑定(bind) singledispatch 的已注册函数调度员返回。 source code for this implementation与旧的 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))

关于python3 : singledispatch in class, 如何分派(dispatch)自身类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24063788/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com