我想本地在python中实现一个不可变类型。我从这里收集了
How to make an immutable object in Python?
最好的方法是覆盖元组。让我们说我想要一个存储一些额外数据的元组。我会做类似的事情:
class MyTuple(tuple):
def __new__(cls, lst, data):
return tuple.__new__(cls, tuple(lst) + (data, ))
现在我想覆盖len函数:
def __len__(self):
return tuple.__len__(self) - 1
我的python版本在家里工作得很好(Python 2.something,但我不知道哪个),但是在我的办公室计算机上(Python 2.7.3)它破坏了切片:如果我做
m = MyTuple([1,2], 0)
print(m[:-1])
我在家里得到(1, )
我会得到(1, 2)
(我实际上没有检查过,但我将问题追溯到这个最小的例子,我想是这样)。所以在一个实现中,切片调用tuple.__len__
,而另一个实现调用MyTuple.__len__
。我不会介意,但一致性会很好。
所以我的问题是:是否有一个强大的解决方案,如果没有,哪个行为将是稳定的?
编辑:正如Leonardo.Z建议的那样,我的家庭" python实际上是Python 3(.4)。我一直在尝试一个新的ide,而没有注意它使用的是哪个Python。
答案 0 :(得分:1)
切片不一定与调用__len__()
有关,尤其不适用于内置类型。
m[:-1]
转换为m.__getitem__(slice(None, -1))
,可以通过调用内部长度函数以一种非常简单的方式处理tuple
类型,这可以忽略__len__
的事实重写的。
Here是函数在内部定义的方式。
它似乎广泛使用PyTuple_GET_SIZE()
。我没有找到它的定义,但我认为它的定义非常简单。
答案 1 :(得分:1)
它是由Python2和Python3的切片实现之间的差异引起的。
在Python3中,obj[x:y]
始终等于obj.__getitem__(slice(x,y))
。但是在Python2中,由于历史原因,一些内置类型(包括元组)使用__getslice__
方法实现了切片运算符。
__getslice__
使用__len__
方法,__getitem__
没有。
只需在Python2和Python3中运行以下代码,您就会明白为什么。
from __future__ import print_function
class MyTuple(tuple):
def __new__(cls, lst, data):
return tuple.__new__(cls, tuple(lst) + (data, ))
def __len__(self):
return tuple.__len__(self) - 1
def __getitem__(self, key):
print("__getitem__() is called. start:%s, end:%s" % (key.start, key.stop))
return super(MyTuple, self).__getitem__(key)
def __getslice__(self, start, end):
print("__getslice__() is called. start:%s, end:%s" % (start,end))
return super(MyTuple, self).__getslice__(start,end)
m = MyTuple([1,2], 0)
print(m[:-1])
根据Python官方文档,当您在子类中更改__getslice__()
实现时,应该覆盖__len__
方法。
参考: