扩展类型的特殊方法

原文: http://docs.cython.org/en/latest/src/userguide/special_methods.html

本页介绍了 Cython 扩展类型当前支持的特殊方法。所有特殊方法的完整列表显示在底部的表格中。其中一些方法的行为与 Python 对应方式不同,或者没有直接的 Python 对应方式,需要特别提及。

注意

此页面上说的所有内容仅适用于使用cdef class语句定义的扩展类型。它不适用于使用 Python class 语句定义的类,其中适用普通的 Python 规则。

声明

必须使用 def 而不是 cdef 声明扩展类型的特殊方法。这不会影响它们的性能 - Python 使用不同的调用约定来调用这些特殊方法。

Docstrings

目前,某些扩展类型的特殊方法并未完全支持 docstrings。您可以在源中放置 docstring 作为注释,但在运行时它不会显示在相应的__doc__属性中。 (这似乎是一个 Python 限制 - 在 <cite>PyTypeObject</cite> 数据结构中没有任何地方放置这样的文档字符串。)

初始化方法:__cinit__()__init__()

初始化对象有两种方法。

您应该在__cinit__()方法中执行对象的基本 C 级初始化,包括分配您的对象将拥有的任何 C 数据结构。您需要注意在__cinit__()方法中执行的操作,因为在调用对象时,该对象可能还不是完全有效的 Python 对象。因此,您应该小心地调用可能触及该对象的任何 Python 操作;特别是它的方法和任何可以被子类型覆盖的东西(因此依赖于它们已经初始化的子类型状态)。

在调用__cinit__()方法时,已为该对象分配了内存,并且已将其初始化为 0 或 null 的任何 C 属性。 (任何 Python 属性也已初始化为 None,但您可能不应该依赖它。)保证您的__cinit__()方法只能被调用一次。

如果扩展类型具有基类型,则在__cinit__()方法之前会自动调用基类型层次结构中的任何现有__cinit__()方法。您无法显式调用继承的__cinit__()方法,基类型可以自由选择是否实现__cinit__()。如果需要将修改后的参数列表传递给基类型,则必须在__init__()方法中执行初始化的相关部分,而不是调用继承方法的常规规则。

任何无法在__cinit__()方法中安全完成的初始化都应在__init__()方法中完成。到__init__()被调用时,该对象是一个完全有效的 Python 对象,所有操作都是安全的。在某些情况下,可能会多次调用__init__()或根本不调用__init__(),因此在这种情况下,您的其他方法应该设计得很稳健。

传递给构造函数的任何参数都将传递给__cinit__()方法和__init__()方法。如果你期望在 Python 中继承你的扩展类型,你可能会发现给__cinit__()方法 <cite></cite> 和 <cite>*</cite> 参数是有用的,这样它就可以接受并忽略额外的参数。否则,任何具有不同签名的__init__()的 Python 子类都必须覆盖__new__() [1] 以及__init__(),Python 类的编写者不会期望得做。或者,为方便起见,如果您声明__cinit__()`方法不带参数(除了 self),它将忽略传递给构造函数的任何额外参数,而不会抱怨签名不匹配。

Note

所有构造函数参数都将作为 Python 对象传递。这意味着不可转换的 C 类型(如指针或 C ++对象)无法从 Cython 代码传递到构造函数中。如果需要,请使用工厂函数来处理对象初始化。直接调用此函数中的__new__()以绕过对__init__()构造函数的调用通常会有所帮助。

有关示例,请参阅现有 C / C ++指针 中的 实例化。

| [1] | https://docs.python.org/reference/datamodel.html#object.new |

定稿方法:__dealloc__()

__cinit__()方法的对应物是__dealloc__()方法,它应该执行__cinit__()方法的反转。您__cinit__()方法中明确分配的任何 C 数据(例如通过 malloc)都应该在__dealloc__()方法中释放。

您需要注意在__dealloc__()方法中执行的操作。在调用__dealloc__()方法时,对象可能已经被部分破坏,并且就 Python 而言可能不处于有效状态,因此您应该避免调用可能触及该对象的任何 Python 操作。特别是,不要调用对象的任何其他方法或做任何可能导致对象复活的事情。如果你坚持只是解除分配 C 数据是最好的。

您无需担心释放对象的 Python 属性,因为在__dealloc__()方法返回后,Cython 将为您完成此操作。

在对扩展类型进行子类化时,请注意,即使重写了超类的__dealloc__()方法,也始终会调用它。这与典型的 Python 行为形成对比,在这种行为中,除非子类显式调用超类方法,否则不会执行超类方法。

Note

扩展类型没有__del__()方法。

算术方法

算术运算符方法(如__add__())的行为与 Python 对应方法不同。这些方法没有单独的“反向”版本(__radd__()等)。相反,如果第一个操作数不能执行操作,则调用第二个操作数的相同方法,操作数的顺序相同。

这意味着您不能依赖这些方法的第一个参数是“自”或正确的类型,并且您应该在决定做什么之前测试两个操作数的类型。如果您无法处理已经给出的类型组合,则应返回 <cite>NotImplemented</cite> 。

这也适用于就地算术方法__ipow__()。它不适用于任何其他始终将 <cite>self</cite> 作为第一个参数的原位方法(__iadd__()等)。

丰富的比较

有两种方法可以实现比较方法。根据应用程序的不同,这种方式可能更好:

  • 第一种方法使用 6 Python 特殊方法 __eq__()__lt__()等。这是 Cython 0.27 以来的新功能,与普通 Python 类完全一样。

  • 第二种方法使用单一特殊方法__richcmp__()。这在一个方法中实现了所有丰富的比较操作。签名是def __richcmp__(self, other, int op)。整数参数op表示要执行的操作,如下表所示:

    <colgroup><col width=”42%”> <col width=”58%”></colgroup> | &LT; | Py_LT | | == | Py_EQ | | &GT; | Py_GT | | &LT = | Py_LE | | != | Py_NE | | &GT; = | Py_GE |

    这些常量可以从cpython.object模块中导入。

__next__()方法

希望实现迭代器接口的扩展类型应该定义一个名为__next__()的方法,而不是下一个方法。 Python 系统将自动提供调用__next__()的下一个方法。 NOT 是否明确地给你的类型一个next()方法,否则可能会发生坏事。

特殊方法表

此表列出了所有特殊方法及其参数和返回类型。在下表中,self 的参数名称用于指示参数具有方法所属的类型。表中未指定类型的其他参数是通用 Python 对象。

您不必将方法声明为采用这些参数类型。如果您声明了不同的类型,则会根据需要执行转换。

一般

https://docs.python.org/3/reference/datamodel.html#special-method-names

| 名称 | 参数 | 返回类型 | 描述 | | —- | —- | —- | —- | | cinit | 自我,…… | | 基本初始化(没有直接的 Python 等价物) | | 在里面 | self, … | | 进一步初始化 | | dealloc | 自 | | 基本的释放(没有直接的 Python 等价物) | | cmp | x,y | INT | 3 路比较(仅限 Python 2) | | str | self | 宾语 | STR(个体经营) | | repr | self | object | 再版(个体经营) | | hash | self | Pyhasht | 散列函数(返回 32/64 位整数) | | 呼叫 | self, … | object | 自(…) | | iter | self | object | 返回序列的迭代器 | | getattr | 自我,名字 | object | 获取属性 | | getattribute | self, name | object | 无条件地获取属性 | | setattr | 自我,名字,val | | 设置属性 | | __delattr | self, name | | 删除属性 |

丰富的比较运算符

https://docs.python.org/3/reference/datamodel.html#basic-customization

您可以选择实现标准的 Python 特殊方法,如__eq__()或单个特殊方法__richcmp__()。根据应用,一种方式或另一种方式可能更好。

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | eq | 自我,是的 | object | 自我== y | | ne | self, y | object | self!= y(如果没有,则回退到__eq__) | | lt | self, y | object | 自我&lt; ÿ | | gt | self, y | object | 自我&gt; ÿ | | le | self, y | object | 自我&lt; = y | | ge | self, y | object | 自我&gt; = y | | richcmp | self,y,int op | object | 为上述所有内容加入了丰富的比较方法(没有直接的 Python 等价物) |

算术运算符

https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | | x, y | object | 二进制 <cite>+</cite> 运算符 | | sub | x, y | object | 二进制 <cite>-</cite> 运算符 | | mul | x, y | object | <cite></cite> 运算符 | | div | x, y | object | <cite>/</cite> 运算符用于旧式划分 | | floordiv | x, y | object | <cite>//</cite> 运算符 | | truediv | x, y | object | <cite>/</cite> 运算符用于新式划分 | | mod | x, y | object | <cite>%</cite>运算符 | | divmod | x, y | object | 组合 div 和 mod | | pow | x,y,z | object | <cite>*</cite> 运算符或 pow(x,y,z) | | neg | self | object | 一元 <cite>-</cite> 运算符 | | pos | self | object | 一元 <cite>+</cite> 运算符 | | abs | self | object | 绝对值 | | nonzero | self | int | 转换为布尔值 | | 倒置 | self | object | <cite>〜</cite>运算符 | | lshift | x, y | object | <cite>&lt;&lt;</cite> 运营商 | | rshift | x, y | object | <cite>&gt;&gt;</cite> 运营商 | | | x, y | object | <cite>&amp;</cite> 运营商 | | 要么 | x, y | object | <cite>|</cite> 运营商 | | xor | x, y | object | <cite>^</cite> 运算符 |

数字转换

https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | int | self | object | 转换为整数 | | | self | object | 转换为长整数 | | 浮动 | self | object | 转换为浮动 | | oct | self | object | 转换为八进制 | | hex | self | object | 转换为十六进制 | | index(仅限 2.5+) | self | object | 转换为序列索引 |

就地算术运算符

https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | 我加 | 自我,x | object | <cite>+ =</cite> 运算符 | | isub | self, x | object | <cite>- =</cite> 运算符 | | imul | self, x | object | <cite> =</cite> 运算符 | | idiv | self, x | object | <cite>/ =</cite> 运算符用于旧式划分 | | ifloordiv | self, x | object | <cite>// =</cite> 运算符 | | truediv | self, x | object | <cite>/ =</cite> 运算符用于新式划分 | | imod | self, x | object | <cite>%=</cite> 运算符 | | pow | x, y, z | object | <cite>* =</cite> 运算符 | | ilshift | self, x | object | <cite>&lt;&lt; =</cite> 运算符 | | irshift | self, x | object | <cite>&gt;&gt; =</cite> 运算符 | | 我和 | self, x | object | <cite>&amp; =</cite> 运算符 | | ior | self, x | object | <cite>| =</cite> 运算符 | | ixor | self, x | object | <cite>^ =</cite> 运算符 |

序列和映射

https://docs.python.org/3/reference/datamodel.html#emulating-container-types

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | len | self | Pyssizet | LEN(个体经营) | | getitem | self, x | object | 自[X] | | setitem | 自我,x,y | | self [x] = y | | delitem | self, x | | del self [x] | | getslice | self,Pyssizet i,Pyssizet j | object | 自[I:j]的 | | __setslice | self,Py_ssize_t i,Py_ssize_t j,x | | 自我[i:j] = x | | __delslice | self, Py_ssize_t i, Py_ssize_t j | | del self [i:j] | | __contains | self, x | int | x 在自我中 |

迭代器

https://docs.python.org/3/reference/datamodel.html#emulating-container-types

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | 下一个 | self | object | 获取下一个项目(在 Python 中称为 next) |

缓冲接口[ PEP 3118 ](没有 Python 当量 - 见注 1)

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | getbuffer | self,Pybuffer <cite>* view</cite> ,int flags | | | | _releasebuffer | self,Py_buffer <cite>* view</cite> | | |

缓冲接口[遗留](没有 Python 等价物 - 见注 1)

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | getreadbuffer | self,Pyssizet i,void <cite> p</cite> | | | | getwritebuffer | self, Py_ssize_t i, void <cite>p</cite> | | | | getsegcount | self,Py_ssize_t <cite>* p</cite> | | | | __getcharbuffer | self,Py_ssize_t i,char <cite>** p</cite> | | |

描述符对象(见注 2)

https://docs.python.org/3/reference/datamodel.html#emulating-container-types

| Name | Parameters | Return type | Description | | —- | —- | —- | —- | | 得到 | 自我,实例,阶级 | object | 获取属性的值 | | | 自我,实例,价值 | | 设置属性值 | | 删除 | 自我,实例 | | Delete attribute |

Note

(1)缓冲区接口旨在供 C 代码使用,不能直接从 Python 访问。它在 Python 2.x 的 Python / C API 参考手册的 6.6 和 10.6 节中描述。它被 Python 2.6 中新的 PEP 3118 缓冲协议取代,并且在 Python 3 中不再可用。有关新 API 的操作指南,见 实现缓冲协议

Note

(2)描述符对象是新式 Python 类的支持机制的一部分。请参阅 Python 文档中对描述符的讨论。另见 PEP 252 ,“使类型看起来更像类”, PEP 253 ,“Subtyping Built-In Types”。