首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >cython子类可以访问其cython超类的私有属性吗?其他的cython类?

cython子类可以访问其cython超类的私有属性吗?其他的cython类?
EN

Stack Overflow用户
提问于 2022-11-19 13:42:58
回答 1查看 29关注 0票数 0

我正在构建cython扩展类型,而且我一直担心必须将类属性公之于众,以便其他扩展类型能够看到它们。但是现在比我还要做子类的时候,我更惊讶了。

以下代码

代码语言:javascript
复制
@cython.cclass
class Base:
    base_attrib = cython.declare(cython.double, 0.0)

@cython.cclass
class Derived(Base):
    derived_attrib = cython.declare(cython.double, 0.0)

@cython.cfunc
def f_on_derived(a: Derived, b: Derived) -> Derived:
    res = Derived.__new__(Derived)
    ad = a.derived_attrib
    bd = b.derived_attrib
    ab = a.base_attrib
    bb = b.base_attrib
    res.derived_attrib = ad + bd
    res.base_attrib = ab + bb
    return res

生成一个.c文件,但编译器随后会发出抱怨。

代码语言:javascript
复制
src/crujisim/cythontests.c(40975): error C2065: 'base_attrib': undeclared identifier
src/crujisim/cythontests.c(40975): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
src/crujisim/cythontests.c(41007): error C2065: 'derived_attrib': undeclared identifier
src/crujisim/cythontests.c(41007): warning C4244: '=': conversion from 'double' to 'int', possible loss of data

因为它是一个C函数,所以我本来希望类型化注释足够了,但事实并非如此。

我可以通过声明公共可见性来编译它,如

代码语言:javascript
复制
@cython.cclass
class Base:
    base_attrib = cython.declare(cython.double, visibility='public')

@cython.cclass
class Derived(Base):
    derived_attrib = cython.declare(cython.double, visibility='public')

但是,res.base_attrib = ab + bb的C代码必须通过python,如

代码语言:javascript
复制
__pyx_t_1 = PyFloat_FromDouble((__pyx_v_ab + __pyx_v_bb))
if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 26, __pyx_L1_error)__Pyx_GOTREF(__pyx_t_1)
if (__Pyx_PyObject_SetAttrStr(__pyx_v_res, __pyx_n_s_base_attrib, __pyx_t_1) < 0) __PYX_ERR(0, 26, __pyx_L1_error)__Pyx_DECREF(__pyx_t_1)
__pyx_t_1 = 0;

所以有两个问题:

  • 可以拥有仅为C但子类可以访问的超类属性吗?

  • 可以拥有类属性,这些类属性仅为C,但在其他情况下对C代码是可见的?

更新--我刚刚注意到,如果不使用快速实例化(即res = Derived()而不是res = Derived.__new__(Derived)属性),就会像预期的那样工作。当然,我现在也失去了快速实例化。

我可以把蛋糕也吃了吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-20 11:46:44

所以有几个问题在这里起作用:

编译器错误是由于包含一个值的属性声明造成的。让它们与base_attrib = cython.declare(cython.double)一样,自动删除警告和初始化为0的值。

另一个问题是,通过快速实例化生成的对象必须通过python来访问其属性,而python实例化没有,这是因为__new__方法生成的是python对象,而不是C版本。因此,在代码中,唯一的问题是访问新实例的属性,而不是作为参数传递的属性。

这是通过声明保存快速实例化返回的对象的变量来解决的。

因此,到目前为止,最初问题的最快版本是

代码语言:javascript
复制
@cython.cclass
class Base:
    base_attrib = cython.declare(cython.double)

@cython.cclass
class Derived(Base):
    derived_attrib = cython.declare(cython.double)

@cython.cfunc
def f_on_derived(a: Derived, b: Derived) -> Derived:
    res: Derived = Derived.__new__(Derived)  # Notice res: Derived
    ad = a.derived_attrib
    bd = b.derived_attrib
    ab = a.base_attrib
    bb = b.base_attrib
    res.derived_attrib = ad + bd
    res.base_attrib = ab + bb
    return res

为了测试速度,我有以下两个功能

代码语言:javascript
复制
@cython.ccall
def python_instantiate() -> Derived:
    o = Derived()
    return o

@cython.ccall
def cython_fast_instantiate() -> Derived:
    o: Derived = Derived.__new__(Derived)
    return o

我们得到他们的时间

代码语言:javascript
复制
In [2]: %timeit python_instantiate()
87.5 ns ± 0.895 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

In [3]: %timeit cython_fast_instantiate()
62.1 ns ± 0.574 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

这证明了快速实例化更快,即使有一些python对象引用增量和递减,我不确定这是完全必要的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74500553

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档