Python继承UserList并使用新属性扩展

s8vozzvw  于 2023-08-08  发布在  Python
关注(0)|答案(3)|浏览(92)

我想用新的属性扩展UserList类(https://docs.python.org/3/library/collections.html#collections.UserList),如下所示:

class GroceryList(UserList):
  def __init__(self, initlist, max_item_weight, max_item_volume):
    super().__init__(initlist)
    self.max_item_weight = max_item_weight
    self.max_item_volume = max_item_volume

字符串
现在,如果我切片GroceryList,我会丢失max_item_weightmax_item_volume属性,所以我会覆盖__getitem__方法:

def __getitem__(self, i):
    if isinstance(i, slice):
        return self.__class__(self.data[i], self.max_item_weight, self.max_item_volume)
    else:
        return self.data[i]


我如何覆盖UserList__getitem__方法,使它更通用,并且我不必为我创建的每个新类型的列表覆盖__getitem__方法,例如:GroceryListToolsListNonEdibleList ...因为我想在分割了派生列表之后保留属性。

kx1ctssn

kx1ctssn1#

您可以复制该对象并仅更改self.data变量。类似于以下内容:

from copy import deepcopy

class UserList2(UserList):
  def __getitem__(self, i):
      if isinstance(i, slice):
          obj = deepcopy(self)
          obj.data = self.data[i]
          return obj
      else:
          return self.data[i]

字符串
然后,您可以按照与继承UserList相同的方式继承这个类。例如,

class GroceryList(UserList2):
  def __init__(self, initlist, max_item_weight, max_item_volume):
    super().__init__(initlist)
    self.max_item_weight = max_item_weight
    self.max_item_volume = max_item_volume

l1 = GroceryList([1,2,3,4,5,6,7,8,9], 7, 6)
print(l1[3:7], l1[3:7].max_item_weight, l1[3:7].max_item_volume)


给出[4, 5, 6, 7] 7 6作为输出,其中list是切片数据,7,6是原始属性。
另一种方法如下,但这需要一些额外的bookeeping和在继承时使用关键字参数。

class UserList2(UserList):
  def __init__(self, initlist, **kwargs):
    super().__init__(initlist)
    self.constants = kwargs.keys()
    for k, v in kwargs.items():
        self.__setattr__(k, v)

  def __getitem__(self, i):
      if isinstance(i, slice):
          return self.__class__(self.data[i], **{k: self.__getattribute__(k) for k in self.constants})
      else:
          return self.data[i]


相同的示例随后更改为:

class GroceryList(UserList2):
  def __init__(self, initlist, max_item_weight, max_item_volume):
    super().__init__(initlist, max_item_weight=max_item_weight, max_item_volume=max_item_volume)

l1 = GroceryList([1,2,3,4,5,6,7,8,9], 7, 6)
print(l1[3:7], l1[3:7].max_item_weight, l1[3:7].max_item_volume)


其给出相同的输出。

dxpyg8gm

dxpyg8gm2#

我有一个很好的解决方案,它虽然能确保所有的方法都能正常工作,但是在一些内置函数上会出现错误,比如isinstance

class NewList(UserList):
    def __init__(self, data, attr, attr2):
        super().__init__(data)
        self.attr = attr
        self.attr2 = attr2

    @property
    def __class__(self):
        return lambda data: type(self)(data, self.attr, self.attr2)

字符串

aiqt4smr

aiqt4smr3#

没有什么好的理由继承collections.UserList而不是list。特别是在这种情况下,拥有data属性会使将自己的附加属性传递给构造函数变得麻烦,因为在将data键解包到构造函数之前,你必须从属性字典中删除它。
通过继承list,您可以以一种干净和通用的方式直接将vars(self)解压缩到构造函数:

class GroceryList(list):
    def __init__(self, initlist, max_item_weight, max_item_volume):
        super().__init__(initlist)
        self.max_item_weight = max_item_weight
        self.max_item_volume = max_item_volume

    def __getitem__(self, i):
        sliced = super().__getitem__(i)
        if isinstance(i, slice):
            return self.__class__(sliced, **vars(self))
        return sliced

l = GroceryList([1, 2, 3], 4, 5)
s = l[1:3]
print(s)
print(s.max_item_weight)
print(s.max_item_volume)

字符串
该输出:

[2, 3]
4
5


演示:https://replit.com/@blhsing/TemptingSourBash

相关问题