如何迭代包含在其他结构中的对象并调用它们的方法(使Cython知道它们)?

时间:2019-01-28 20:05:54

标签: cython

当我遍历相同类型(或派生类)的对象并在循环内调用相同方法时,方法将无法识别。

当我遍历已定义的类中的数据结构(在这种情况下为collections.OrderedDict)中存储的对象时,会发生这种情况。我已经在pxd文件中将这些方法提供给Cython。

无论MyClass是基类还是派生类,都会发生这种情况。

我正在使用unittest测试我的代码。

我想知道Cython是否不支持此功能,或者在对象扩展为Cython时是否缺少有关该对象的某些信息。

myclass.pxd

cdef class MyClass():
    cdef public object _dict
    cdef void add_obj(self, name, obj)
    cdef void m(self)
    cdef void _m(self)

myclass.pyx

from collections import OrderedDict
cdef class MyClass():
    def __cinit__(self):
        self._dict = OrderedDict()

    cdef void add_obj(self, name, obj):
        self._dict[name] = obj 

    cdef void m(self):
        # user defines this in derived class
        pass

    cdef void _m(self):
        cdef int i = 0
        print('running user defined method')
        self.m()
        print(self._dict.keys())
        print('adding objects')
        for key, obj in self._dict.items():
            # ERROR
            print('obj')
            print(obj)
            obj.m()
            i += 1
            print('added an object')
            print(i)

test.pyx

from mypkg.core.myclass cimport MyClass
import unittest

cdef class ChildClass(MyClass):
    cdef void m(self):
        self.add_obj('a', MyClass())
        self.add_obj('b', MyClass())
        self.add_obj('c', MyClass())

cdef class ParentClass(MyClass):
    cdef void m(self):
        self.add_obj('a', ChildClass())
        self.add_obj('b', ChildClass())
        self.add_obj('c', ChildClass())

cdef ParentClass H = ParentClass()

class SetupTree(unittest.TestCase):
    def setUp(self):
        H._m()

    def test_tree(self):
        print(H._dict)
        print(len(H._dict))

输出

running user defined method
odict_keys(['a', 'b', 'c'])
adding objects
obj
<mypkg.test.test_system2.ChildClass object at 0x7f86ff915b38>
AttributeError: 'mypkg.test.test_system2.ChildClass' object has no attribute 'm'
Exception ignored in: 'mypkg.core.group.MyClass._m'
AttributeError: 'mypkg.test.test_system2.ChildClass' object has no attribute 'm'
OrderedDict([('a', <mypkg.test.test_system2.ChildClass object at 0x7f86ff915b38>), ('b', <mypkg.test.test_system2.ChildClass object at 0x7f86ff915d30>), ('c', <mypkg.test.test_system2.ChildClass object at 0x7f86ff915c88>)])
3
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

1 个答案:

答案 0 :(得分:0)

cdef方法只有在编译时可以找到时才能被调用-在运行时不能将它们视为Python属性。您没有在_m中做任何事情来告诉Cython objMyClass,因此它不知道cdef方法的存在。

您有两个选择:

  1. cdef m(...)更改为def(或cpdef),以便Python在运行时可以找到它。

  2. 告诉Cython objMyClass的实例:

    cdef MyClass obj # you'll receive an TypeError exception if you ever 
         # attempt to assign something that isn't a MyClass to obj
    for key, obj in self._dict.items():
        obj.m() # now works!