我需要一个新类型,比如说MyTuple
,这样我就可以创建这样的对象:obj = MyTuple((1,2,3))
,例如:
obj
的行为与本机元组完全相同(也在性能方面)isinstance(obj, tuple)
返回False
。这背后的原因是我需要在Pandas中使用元组作为索引,但是当Pandas检测到索引的值是元组时,它使用多索引代替,这是我不想要的。
因此,以下内容不起作用:
class MyTuple(tuple):
pass
这满足了我的第一个要求,但不满足第二个要求,所以如果我使用MyTuple
个对象作为索引,Pandas仍会从它们创建多索引。
另一种解决方案是使用组合而不是继承,实现Sequence
abc并将真元组作为对象属性,为它提供包装方法:
from collections.abc import Sequence
class MyTuple(Sequence):
def __init__(self, initlist=None):
self.data = () # A true tuple is stored in the object
if initlist is not None:
if type(initlist) == type(self.data): self.data = initlist
elif isinstance(initlist, MyTuple): self.data = initlist.data
else: self.data = tuple(initlist)
def __getitem__(self, i): return self.data[i]
def __len__(self): return len(self.data)
def __hash__(self): return hash(self.data)
def __repr__(self): return repr(self.data)
def __eq__(self, other): return self.data == other
def __iter__(self): yield from self.data.__iter__()
此类型满足第二个要求(isinstance(obj, tuple)
返回False
),并提供与真实tuple
相同的接口(您可以通过索引访问元素,您可以将其与另一个元组,你可以用它作为字典键等)。在语法和语义上这个解决方案对我有好处。
然而,就性能而言,它不是真正的tuple
。在我的应用程序中,我必须在这些对象(以及具有真tuple
s的这些对象)之间进行大量的比较,因此方法MyTuple.__eq__()
被称为很多次。这引入了性能损失。使用MyTuple
而不是真元组,我的程序将运行时间乘以6。
然后,我需要的是像我的第一次尝试(一个继承自tuple
的类),但后来可以"谎言"关于成为一个元组,如果通过isinstance()
询问(因为这是Pandas如果发现它是一个元组,因此应该创建一个多索引)。
我读过Python的datamodel和__instancecheck__()
方法,但我认为它们在这里没用,因为我应该在tuple
中实现这些方法,而不是{ {1}},但这是不可能的。
也许有一些使用元类的技巧会做到这一点,但我并不完全理解这个概念,看它与这个问题的关系。
我可以以某种方式实现我的目标吗?
答案 0 :(得分:1)
tuple
类似的其他方法。
仍然不是真正的{{1}}表现,但我能想到的最接近......可能。
答案 1 :(得分:0)
您在性能方面遇到的主要问题是,Python的基础资料是在高度优化的C(或其他语言 - 有十几个好的实现,还有更多的实现)中实现的。
当您在Python中实现某些内容时,请记住它的解释或部分编译最多。如果必须在运行时重新解释每一行,即使给出了良好的中间代码,也无法获得最佳性能。