2015-10-19 108 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