是否应该为cython扩展类型中的“self”参数提供类型信息?

时间:2017-10-16 00:40:36

标签: cython

我一直在尝试用cython包装C ++。我试图理解在扩展类型方法中输入<li key = {country.id}> <Country country={country}> </li> 的含义。

docs self未明确输入,但似乎可能会有与点击self相关联的加速。

但是,在我有限的实验中,明确键入self似乎不会产生性能提升。封面下是否有特殊的魔法可以处理self,或者这纯粹是一种风格的东西?

为清晰起见,

编辑

通过键入self,我的意思是提供方法的self参数的类型信息。即:

self

VS

cdef class foo:
    cpdef bar(self):
        # do stuff with self

2 个答案:

答案 0 :(得分:2)

简答:

在类方法中不需要详细类型self。它并不比普通的self快。

答案很长:

虽然生成的c代码确实存在一些差异(人们可以使用魔法单元%%cython -a轻松地在jupyter笔记本中查看它)。例如:

%%cython -a

# Case 1
cdef class foo1:
    def bar(self, foo1 other):
        pass
    def __eq__(self, foo1 other):
        pass

# Case 2
cdef class foo2:
    def bar(self, foo2 other):
        pass
    def __eq__(foo2 self, foo2 other):
        pass
  1. 在Python包装器中,self始终转换为PyObject *

  2. 对于普通方法(bar),包装的C函数签名是相同的,self都转换为struct xxx_foo *

  3. 对于魔术方法(__eq__),在包装的C函数中,普通self转换为PyObject *,但键入的foo2 self将转换为{ {1}}。在后一种情况下,python包装器将struct xxx_foo2 *强制转换为PyObject *并调用包装的C函数。情况2可能具有较少的指针间接,但在两种情况下性能应该没有太大差异。此外,案例2将在python包装器中进行更多检查。在实践中,个人资料可以说出一切。

答案 1 :(得分:1)

正如您已经解决的那样,通常self会在生成的c代码中“翻译”为正确的类型。

我所知道的唯一例外是rich comparison operators,即__eq____lt____le__等等。

+=+等其他特殊方法/运算符的工作方式与所有其他“常规”方法完全相同:self自动为正确类型。

但是,丰富的比较运算符的行为很快就会改变,因为它似乎只是新引入的功能中的一个小故障:corresponding issue

现在,我们已经建立了,cython做了什么,有趣的问题是为什么cython这样做。

对于某些来自静态类型语言的人来说很明显,self只能是定义了这个函数的类类型(确切地说是这个类或派生自这个类),所以我希望self属于此类类型。因此,如果cython表现不同,那将是一个惊喜。

然而,在可以动态更改类的鸭子类型和mokey-patching时代可能并不那么清楚。我们来看看下面的例子:

 []class A:
    def __init__(self, val):
         self.val=val
    def __str__(self):
       return "value=%s"%self.val

 []class B:
     def __init__(self, val):
        self.val="<"+val+">"

 [] a,b=A(1.0),B("div")
 [] print a
 value=3
 [] print b
 <__main__.B instance at 0x0000000003D24E08>

因此,如果我们不喜欢print处理类B的方式。可以通过以下方式对类B进行修补:

 []B.__str__=lambda self: "value=%s"%self.val
 []print b
 value=<div>

因此,如果我们喜欢类A处理__str__方法的方式,我们可以尝试“重用”它:

 []B.__str__=lambda self: A.__str__(self)
 []print b
 TypeError: unbound method __str__() must be called 
            with A instance as first argument 
            (got B instance instead)

所以这是不可能的:python检查对A.__str__(self)的调用,self实际上是A类型。

因此,cython直接使用self的正确类型而不是python对象是正确的。