我一直在尝试用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
答案 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
在Python包装器中,self
始终转换为PyObject *
。
对于普通方法(bar
),包装的C函数签名是相同的,self
都转换为struct xxx_foo *
。
对于魔术方法(__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对象是正确的。