从元组子类继承

2024-05-26 22:58:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用的是第三方模块,它提供从tuple继承的类。但是,我想在这些类中添加一些功能,所以我有了子类。结果继承层次结构如下所示:

MyClass->;LibClass->;tuple

tuple子类的继承有什么原因应该是预期的失败吗?在

血淋淋的细节

一开始一切似乎都很好。但是,使用切片(instance[:6])从MyClass的实例访问一系列值会导致如下错误:

SystemError: <method-wrapper '__getitem__' of LibClass object at 0x1010101010> returned NULL without setting an error

LibClass的实例执行完全相同的操作可以完美地工作。在

为了进一步增加神秘感,对MyClass实例的常规索引访问(instance[5])可以完美地工作。在

显然tuple继承与正则类继承不同(即__new__必须被重写,而不是{})。然而,据我所知,LibClass是正确的

def __new__(cls, *members):
    mat = [x * 1.0 for x in members] + [0.0, 0.0, 1.0]
    return tuple.__new__(cls, mat)

我不认为在MyClass中实现__new__是必要的,因为LibClass中的实现正确地通过了{}(必须承认,为了实现这一点,我不得不分叉库)。尽管如此,对于后代,我也尝试过直接在MyClass中实现__new__(只是复制并粘贴了LibClass实现)。在

我还应该注意到我在MyClass中没有做任何古怪的事情。如果问题仍然存在,那就什么也不做

^{pr2}$

另一件值得注意的事情是,LibClass没有自定义的__getitem__实现,它只是从tuple继承该行为。在

Python 3.6.1

额外的血淋淋的(真实的)细节

LibClass实际上Affine来自planar,我的叉子可以在这里找到:

https://github.com/Benjamin-Dobell/planar/blob/master/lib/planar/transform.py

再生产

pip install git+https://github.com/Benjamin-Dobell/planar#egg=planar
python

>>> import planar
>>> class Affine(planar.Affine):
...     pass
... 
>>> planar.Affine.identity()[:6]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0)
>>> Affine.identity()[:6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: <method-wrapper '__getitem__' of Affine object at 0x10e2b9ba8> returned NULL without setting an error

在评论中指出,在上面的复制中,identity()返回一个常量。所以它不应该失败。我无法解释。不过,我应该补充一点,这是一个相当差的复制我。我的实际使用量更接近于:

>>> Affine.translation((0, 0))[:6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: <method-wrapper '__getitem__' of Affine object at 0x10f8d5ee8> returned NULL without setting an error
>>> planar.Affine.translation((0, 0))[:6]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0)

但同样失败了。在

请注意,这种不断的失败真让我抓狂。在

一些planar特定的东西

尝试不同的Python版本时,同样失败:

3.3.6

Python 3.3.6 (default, Apr 12 2017, 17:20:32) 
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import planar
>>> class Affine(planar.Affine):
...     pass
... 
>>> planar.Affine.identity()[:6]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0)
>>> Affine.identity()[:6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: NULL result without error in PyObject_Call

2.7.11

Python 2.7.11 (default, May  2 2016, 14:38:51) 
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import planar       
>>> class Affine(planar.Affine):
...     pass
... 
>>> planar.Affine.identity()[:6]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0)
>>> Affine.identity()[:6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: NULL result without error in PyObject_Call

但是,当把问题简化为最简单的形式时,我无法重现这个问题(Python 2.7.11):

>>> class LibClass(tuple):
...     def __new__(cls, *members):
...         return tuple.__new__(cls, *members)
... 
>>> class MyClass(LibClass):
...     pass
... 
>>> LibClass((1, 2, 3, 4, 5))[:3]
(1, 2, 3)
>>> MyClass((1, 2, 3, 4, 5))[:3]
(1, 2, 3)

我还尝试将LibClass的定义移动到一个单独的lib.py,以确保错误与Python模块无关,但它的工作原理如上所述。在

所以这个问题是planar和/或其Affine类特有的问题。不过,如果能确切知道是什么导致了这个问题,那就太好了。在


Tags: innewmyclasserrornullidentityclasscls
1条回答
网友
1楼 · 发布于 2024-05-26 22:58:12

事实证明确实涉及到一个有缺陷的扩展模块。planar根本没有使用您编辑过的planar.transform模块;它使用的是planar.c,这是planar功能的一个C实现,带有自己的Affine类。在

问题至少有一部分似乎是由于^{}中的错误造成的:

static PyObject *
Affine_getitem(PlanarAffineObject *self, Py_ssize_t i)
{
    double m;

    assert(PlanarAffine_Check(self));
    if (i < 6) {
        m = self->m[i];
    } else if (i < 8) {
        m = 0.0;
    } else if (i == 8) {
        m = 1.0;
    } else {
        return NULL;
    }
    return PyFloat_FromDouble(m);
}

其中,它返回NULL,而不为超出范围的索引设置IndexError。在

planar不再维护,因此不会处理错误报告。可能有更好的模块可以使用。在

相关问题 更多 >

    热门问题