【问题标题】:Emulating the list.insert() method as a subclass of Python's list将 list.insert() 方法模拟为 Python 列表的子类
【发布时间】:2011-04-07 19:31:51
【问题描述】:

我正在尝试构建一个继承 Python 列表中的方法的类,但还做了一些额外的事情......此时仅显示代码可能更容易......

class Host(object):
    """Emulate a virtual host attached to a physical interface"""
    def __init__(self):
    # Insert class properties here...
    pass

class HostList(list):
    """A container for managing lists of hosts"""
    def __init__(self):
        self = []

    def append(self, hostobj): 
        """append to the list...""" 
        if hostobj.__class__.__name__ == 'Host': 
            self.insert(len(self), hostobj)
        else:
            _classname = hostobj.__class__.__name__
            raise RuntimeError, "Cannot append a '%s' object to a HostList" % _classname

我的问题是...如果我想在 insert() 上执行与在 append() 上相同的对象接纳测试,我找不到在不牺牲支持的情况下编写新方法的方法对于一种列表扩展方法(即list.append()list.insert()list.extend())。如果我尝试支持所有这些,我会以递归循环结束。解决此问题的最佳方法是什么?

编辑:我接受了关于子类化 collections.MutableSequence 而不是 Python 的 list() 的建议

生成的代码...张贴在这里以防万一,它可以帮助某人...

from collections.abc import MutableSequence
class HostList(MutableSequence):
    """A container for manipulating lists of hosts"""
    def __init__(self, data):
        super(HostList, self).__init__()
        if (data is not None):
            self._list = list(data)
        else:
            self._list = list()

    def __repr__(self):
        return "<{0} {1}>".format(self.__class__.__name__, self._list)

    def __len__(self):
        """List length"""
        return len(self._list)

    def __getitem__(self, ii):
        # Good MutableSequence() implementation example in the cpython git repo:
        #    https://github.com/python/cpython/blob/208a7e957b812ad3b3733791845447677a704f3e/Lib/collections/__init__.py#L1215
        if isinstance(ii, slice):                                               
            return self.__class__(self._list[ii])                                
        else:                                                                   
            return self._list[ii] 

    def __delitem__(self, ii):
        """Delete an item"""
        del self._list[ii]

    def __setitem__(self, ii, val):
        # optional: self._acl_check(val)
        return self._list[ii]
    def __str__(self):
        return str(self._list)
    def insert(self, ii, val):
        # optional: self._acl_check(val)
        self._list.insert(ii, val)
    def append(self, val):
        self.insert(len(self._list), val)

【问题讨论】:

  • self = [] 并没有按照你的想法去做。
  • super(HostList, self).__init__(self) 可以解决问题。您的代码所做的是将(参数)变量self 重新分配给[]
  • 如果指定了切片,__getitem__ 将返回一个列表对象。您可以将初始值设定项更改为__init__(self, l = None),如果提供,它将使用列表。然后在__getitem__中,如果ii是切片对象,则返回HostList(self._list[ii])
  • 另外,您不必定义 append() 方法,因为 MutableSequence 已经为您完成了,只要您定义了 insert() 方法(查看 hg.python.org/cpython/file/3.4/Lib/_collections_abc.py#l711 了解更多信息信息)。
  • PyCharm 告诉我您缺少几个抽象方法:__iter__()__contains__()

标签: python list subclassing


【解决方案1】:

如果可以避免,请不要从内置类继承。 (你可以,但这并不意味着你应该没有真正令人信服的理由)

这些类针对速度进行了优化,这使得从它们正确继承非常乏味,因为您最终不得不覆盖几乎所有内容。

collections.MutableSequence 继承可以让您只实现一些基本方法,并获得序列API 的功能强大的全功能实现,而没有从list 继承所带来的所有怪癖和警告。

【讨论】:

  • 好点+1...经过一番努力,我得到了它与collections.MutableSequence...谢谢!
【解决方案2】:

使用isinstance 来检查您的对象以查看它们是否是Host 的实例,并使用super(例如super(HostList, self).insert(...))来使用list 的功能,而不是自己重新实现它。

你应该得到类似的结果:

def append(self, obj): 
    """append to the list..."""
    if not isinstance(obj, Host):
        raise RuntimeError, "Cannot append a '%s' object to a HostList" % obj.__class__.__name__
    super(HostList, self).append(obj)

【讨论】:

  • 更好的是,定义一个静态方法as_host(x),如果它是主机则返回x,否则抛出适当的异常。然后super 调用就变成了单行。
【解决方案3】:

除非有令人信服的理由让您的 HostList 容器完全支持可变容器接口,否则我建议使用 has-a 模型而不是 is-a。您将有额外的负担来确保与切片等操作的类型一致性(返回 HostList 容器而不是列表)。

【讨论】:

    【解决方案4】:

    您可以使用super() 从您的方法中调用list 的方法。这样你就不需要和其他方法混在一起了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-24
      • 1970-01-01
      • 2018-09-08
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多