【发布时间】:2018-06-18 19:07:02
【问题描述】:
我在玩 Cython,更深入地研究 kivy,我一直在尝试制作自己的 Kivy 财产。
我有以下文件定义 DocProperty: my.pyx:
from kivy.properties cimport Property, PropertyStorage
from kivy._event cimport EventDispatcher
cdef inline void observable_object_dispatch(object self, str name):
cdef Property prop = self.prop
prop.dispatch(self.obj, name)
class ObservableObject(object):
# Internal class to observe changes inside a native python object.
def __init__(self, *largs):
self.prop = largs[0]
self.obj = largs[1]
super(ObservableObject, self).__init__()
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
observable_object_dispatch(self, name)
cdef class DocProperty(Property):
def __init__(self, defaultvalue=None, rebind=False, **kw):
self.baseclass = kw.get('baseclass', object)
super(DocProperty, self).__init__(defaultvalue, **kw)
self.rebind = rebind
cpdef link(self, EventDispatcher obj, str name):
Property.link(self, obj, name)
cdef PropertyStorage ps = obj.__storage[self._name]
ps.value = ObservableObject(self, obj, ps.value)
cdef check(self, EventDispatcher obj, value):
if Property.check(self, obj, value):
return True
if not isinstance(value, object):
raise ValueError('{}.{} accept only object based on {}'.format(
obj.__class__.__name__,
self.name,
self.baseclass.__name__))
cpdef dispatch(self, EventDispatcher obj, str name):
'''Dispatch the value change to all observers.
.. versionchanged:: 1.1.0
The method is now accessible from Python.
This can be used to force the dispatch of the property, even if the
value didn't change::
button = Button()
# get the Property class instance
prop = button.property('text')
# dispatch this property on the button instance
prop.dispatch(button)
'''
cdef PropertyStorage ps = obj.__storage[self._name]
ps.observers.dispatch(obj, ps.value, (name,), None, 0)
from kivy.properties cimport Property, PropertyStorage
from kivy._event cimport EventDispatcher
cdef class DocProperty(Property):
cdef object baseclass
cdef public int rebind
cpdef dispatch(self, EventDispatcher obj, str name)
快速试用一下:my.py
# -*- coding: utf-8 -*-
from kivy.event import EventDispatcher
import pyximport
pyximport.install()
from properties import DocProperty
if __name__ == '__main__':
class ED(EventDispatcher):
doc = DocProperty()
def on_doc(self, obj, value):
print 'printing doc', self.doc
class DumbObj(object):
def __init__(self, num):
self._num = num
@property
def num(self):
return 5
@num.setter
def num(self, value):
self._num = value
ed = ED()
ed.doc = DumbObj(3)
ed.doc.num = 4
当我运行 my.py 时,我在 DocProperty 的调度方法上得到一个“签名与先前的声明不兼容”,因为我尝试在 Property 上覆盖它的声明,以便它可以接受比原始代码声明更多的参数。是否可以重载在 pxd 上声明的 cpdef 方法?如果是这样,我做错了什么?
编辑:
在@ead's suggestion 之后,我尝试在dispatch 的声明中用普通的def 替换cpdef 语句,同时在两个文件上,一次只在其中一个文件上。但这没有任何效果。然后我尝试注释掉对 dispatch 的调用,看看如果它没有编译失败会发生什么。原来 DocProperty 的两个属性(基类和绑定)在赋值时都会引发 AttributeError。这很奇怪,因为这些是从 Kivy 源复制/粘贴的。这意味着 my.pxd 文件对我的 Cython 代码没有任何影响?我尝试从 cimporting my.pxd 到 my.pyx,但这也没有产生结果
【问题讨论】:
标签: python overriding kivy cython