2015-10-19 111 views
2

如何我必须用Cython重写RMUL正确覆盖

例如,这完全在蟒蛇

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的。

回答

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以及/或检查更通用的号码类型。

+0

谢谢!是的,我很内疚。我没有查看文档,我在谷歌搜索了很多(通常我得到更好的答案,当问题是,一定是行不通的事情)。 我的歉意,再次感谢。 – diego