我如何在cython中覆盖 rmul ?
例如,这在python中非常有效
class PyFoo:
def __init__(self):
self.a = 4
def __mul__(self,b): return b*self.a
def __rmul__(self,b): return self*b
Pynew = PyFoo()
print " Python "
print Pynew*3 # I got 12
print 3*Pynew # I got 12
但是,如果我在Cython中实现相同功能,
cclass.pyx
cimport cython
cdef class Foo:
cdef public int a
def __init__(self):
self.a = 4
def __mul__(self,b): return b*self.a
def __rmul__(self,b): return self*b
test.py
import cclass as c
Cnew = c.Foo()
print " Cython "
print Cnew*3 # This works, I got 12
print 3*Cnew # This doesn't
我收到了这个错误
Traceback (most recent call last):
File "test.py", line 22, in <module>
print 3*Cnew
File "cclass.pyx", line 8, in cclass.Foo.__mul__ (cclass.c:763)
def __mul__(self,b): return b*self.a
AttributeError: 'int' object has no attribute 'a'
我不明白在Cython中使用 rmul 的相同实现有什么问题。
答案 0 :(得分:1)
这是不阅读文档的情况。在Special Methods of Extension Types用户指南中,您会找到以下内容:
算术运算符方法(例如__add __())的行为方式不同 来自他们的Python同行。没有单独的“逆转” 这些方法的版本(__radd __()等)相反,如果是第一个 操作数不能执行操作,第二种方法相同 调用操作数,操作数的顺序相同。
这意味着您不能依赖这些方法的第一个参数 是“自我”或是正确的类型,你应该测试的类型 两个操作数在决定做什么之前。如果你不能处理 你已经给出的类型组合,你应该返回 NotImplemented。
所以你应该按照以下方式进行一些类型检查:
cdef class Foo:
cdef public int a
def __init__(self):
self.a = 4
def __mul__(first, other):
if isinstance(first, Foo):
return first.a * other
elif isinstance(first, int):
return first * other.a
else:
return NotImplemented
此解决方案对Foo
类的使用过于乐观,您可能需要检查other
的类型,和/或检查更通用的数字类型。