Python 从元组子类继承

Python 从元组子类继承,python,python-3.x,inheritance,tuples,Python,Python 3.x,Inheritance,Tuples,我正在使用一个第三方模块,它提供从元组继承的类。但是,我想给这些类添加一些功能,所以我有子类。生成的继承层次结构如下所示: MyClass->LibClass->tuple 从元组子类继承失败有什么原因吗 血淋淋的细节 起初一切似乎都很美好。但是,使用切片(instance[:6])从MyClass的实例访问一系列值会导致如下错误: SystemError:返回NULL而未设置错误 对LibClass的实例执行完全相同的操作是完美的 为了进一步增加神秘性,对MyClass实例的常规索引访问(in

我正在使用一个第三方模块,它提供从
元组继承的类。但是,我想给这些类添加一些功能,所以我有子类。生成的继承层次结构如下所示:

MyClass
->
LibClass
->
tuple

元组
子类继承失败有什么原因吗

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

SystemError:返回NULL而未设置错误

LibClass
的实例执行完全相同的操作是完美的

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

显然,
元组
继承与常规类继承并不完全相同(即,
\uuuuuu新的\uuuuuuu
必须被重写,而不是
\uuuuu初始化\uuuuuuuuu
)。然而,据我所知,
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
中实现
\uuu new
是必要的,因为
LibClass
中的实现正确地通过了
cls
(无可否认,我必须使用库来实现这一点)。尽管如此,对于后代,我也尝试过直接在
MyClass
中实现
\uuuu new
(只是复制并粘贴了
LibClass
实现)

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

class MyClass(lib.LibClass):
    pass
另一件值得注意的事情是,
LibClass
没有自定义的
\uuu getitem\uuu
实现——它只是从
元组继承了该行为

Python 3.6.1

额外的血淋淋的(真实的)细节
LibClass
实际上是
Affine
来自
planar
,我的fork可以在这里找到:

繁殖
pip安装git+https://github.com/Benjamin-Dobell/planar#egg=planar
python
>>>导入平面
>>>类仿射(平面仿射):
...     通过
... 
>>>planar.Affine.identity()[:6]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0)
>>>Affine.identity()[:6]
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
SystemError:返回NULL而未设置错误
评论中指出,在上述复制中,
identity()
返回一个常量。所以它真的不应该失败。我无法解释。然而,我可能应该补充一点,那是一个相当糟糕的复制我。我在现实世界中的使用更接近:

仿射翻译((0,0))[:6] 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 SystemError:返回NULL而未设置错误 >>>平面仿射平移((0,0))[:6] (1.0, 0.0, 0.0, 0.0, 1.0, 0.0)
这也以同样的方式失败了

请注意,不断的失败真的让我抓狂

平面的东西 尝试不同的Python版本时,同样会失败:

3.3.6
Python 3.3.6(默认值,2017年4月12日,17:20:32)
达尔文上的[GCC 4.2.1兼容苹果LLVM 8.1.0(clang-802.0.38)]
有关详细信息,请键入“帮助”、“版权”、“信用证”或“许可证”。
>>>导入平面
>>>类仿射(平面仿射):
...     通过
... 
>>>planar.Affine.identity()[:6]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0)
>>>Affine.identity()[:6]
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
SystemError:PyObject_调用中无错误的空结果
2.7.11
Python 2.7.11(默认,2016年5月2日,14:38:51)
[GCC 4.2.1达尔文兼容苹果LLVM 7.3.0(clang-703.0.29)]
有关详细信息,请键入“帮助”、“版权”、“信用证”或“许可证”。
>>>导入平面
>>>类仿射(平面仿射):
...     通过
... 
>>>planar.Affine.identity()[:6]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0)
>>>Affine.identity()[:6]
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
SystemError:PyObject_调用中无错误的空结果
但是,当简化为最简单的形式时,我无法重现问题(Python 2.7.11):

类LibClass(元组): ... 定义新成员(cls,*成员): ... 返回元组。\uuuu新建\uuuuu(cls,*成员) ... >>>类MyClass(LibClass): ... 通过 ... >>>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
没有使用您编辑的
planar.transform
模块;它使用的是
planar.c
,这是
planar
功能的c实现,它有自己的
仿射类

至少部分问题似乎是由于以下方面的错误造成的:

静态PyObject*
仿射对象(平面仿射对象*self,Py\u-ssize\t i)
{
双m;
断言(平面烷烃检查(自我));
如果(i<6){
m=自我->m[i];
}否则如果(i<8){
m=0.0;
}else如果(i==8){
m=1.0;
}否则{
返回NULL;
}
从double返回PyFloat_(m);
}
其中,它返回
NULL
,而不为超出范围的索引设置
索引器


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

这不应该失败。它们的子类是用C写的吗?你能告诉我们真实的情况吗
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);
}