我有以下代码:
class Mylist(list):
def __init__(self,lst=[]):
self.lst=list(lst)
def append(self,item):
self.lst.append(item)
m=Mylist([1,2])
m.append(3)
m
直观地说,这段代码应该打印[1,2,3]或者[3]?但绝对不是[]。我想知道为什么会这样?虽然当我使用m.lst而不是m时,它会打印[1,2,3]。
答案 0 :(得分:3)
由于MyList
继承自list
,因此它已包含append
(和extend
)通常会添加的项目的内部存储空间。当您print(m)
时,会显示此内部存储空间。
在您的情况下,您已覆盖append
以重定向要添加到单独属性(lst
)的项目,这意味着内部存储空白。
请注意,您尚未覆盖extend
。因此:
# this will add to the *internal* storage, not `.lst`
>>> m.extend(["my", "gosh"])`
>>> print(m)
['my', 'gosh']
答案 1 :(得分:0)
Mylist
不以任何方式利用它的子类list
这一事实。如果list
实际上有一个lst
属性本身就是一个列表,那么你的代码就可以工作,但事实并非如此。
如果希望覆盖的方法执行基础list
对象拾取的操作,则需要使用从中继承的list
对象的公开接口:
class MyList(list):
def __init__(self, iterable):
print('I was passed:', iterable)
super().__init__(iterable)
def append(self, element):
print('I am appending the element:', element)
super().append(element)
答案 2 :(得分:0)
如果您只想使用列表,则无需继承list
,也不应该继承:
class Mylist: # no (list) here!
def __init__(self,lst=[]):
self.lst=list(lst)
def append(self,item):
self.lst.append(item)
m=Mylist([1,2])
m.append(3)
这很有效。当然,打印m
会让你得到像<__main__.MyList at 0x12345678>
这样的东西,因为你没有告诉它你想要如何打印。您需要添加另一种方法:
def __repr__(self):
return '{}({})'.format(type(self).__name__, self.lst)
现在你打印出MyList([1, 2, 3])
。
如果您希望外观,就像list
一样,您仍然不会从list
继承。在大多数情况下,在Python中,“看起来像列表”只是鸭子打字的问题:你实现所有正确的方法,一切正常。
但是,您可能需要考虑从MutableSequence
继承。然后,您只需实现大约7或8个方法,并且您可以免费获得list
的所有其余行为。而且你还提供了一种代码,无论出于什么原因,需要明确检查你是否“像列表一样”的代码可以这样做。
那么,当应该你从list
继承?当您想要将list
的内部存储和实现用作您自己的存储和实现时。
这是一个愚蠢的例子。如果它有任何理由存在,那么它应该是list
子类是合理的:
class FreezableList(list):
def frozen_copy(self):
return tuple(self)
def __repr__(self):
return '{}({})'.format(type(self).__name__, self.lst)