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);
}