python - 让一个类表现得像 Python 中的一个列表

标签 python list python-3.x

我有一个类,它本质上是事物的集合/列表。但我想在这个列表中添加一些额外的功能。我想要的是以下内容:

  • 我有一个实例 li = MyFancyList()。每当我将变量 li 用作列表时,它的行为都应该像列表一样:[e for e in li], li.expand(...) , for e in li.
  • 另外它应该有一些特殊的功能,如 li.fancyPrint()li.getAMetric()li.getName()

我目前使用以下方法:

class MyFancyList:
  def __iter__(self): 
    return self.li 
  def fancyFunc(self):
    # do something fancy

这可以用作 [e for e in li] 之类的迭代器,但我没有像 li.expand(...) 这样的完整列表行为>.

第一个猜测是将 list 继承到 MyFancyList 中。但这是推荐的pythonic方式吗?如果是,需要考虑什么?如果没有,有什么更好的方法?

最佳答案

如果您只想要列表行为的一部分,请使用组合(即您的实例包含对实际列表的引用)并仅实现您想要的行为所需的方法。这些方法应该将工作委托(delegate)给您的类的任何实例所引用的实际列表,例如:

def __getitem__(self, item):
    return self.li[item] # delegate to li.__getitem__

单独实现 __getitem__ 将为您提供数量惊人的功能,例如迭代和切片。

>>> class WrappedList:
...     def __init__(self, lst):
...         self._lst = lst
...     def __getitem__(self, item):
...         return self._lst[item]
... 
>>> w = WrappedList([1, 2, 3])
>>> for x in w:
...     x
... 
1
2
3
>>> w[1:]
[2, 3]

如果您想要列表的完整行为,请从 collections.UserList 继承. UserList 是列表数据类型的完整 Python 实现。

那为什么不直接从list继承呢?

直接从list(或任何其他用C 编写的内置函数)继承的一个主要问题是内置函数的代码可能会或可能不会调用用户定义的类中覆盖的特殊方法。这是 pypy docs 的相关摘录:

Officially, CPython has no rule at all for when exactly overridden method of subclasses of built-in types get implicitly called or not. As an approximation, these methods are never called by other built-in methods of the same object. For example, an overridden __getitem__ in a subclass of dict will not be called by e.g. the built-in get method.

另一个引述,来自 Luciano Ramalho 的 Fluent Python ,第 351 页:

Subclassing built-in types like dict or list or str directly is error- prone because the built-in methods mostly ignore user-defined overrides. Instead of subclassing the built-ins, derive your classes from UserDict , UserList and UserString from the collections module, which are designed to be easily extended.

...还有更多,第 370 页以上:

Misbehaving built-ins: bug or feature? The built-in dict , list and str types are essential building blocks of Python itself, so they must be fast — any performance issues in them would severely impact pretty much everything else. That’s why CPython adopted the shortcuts that cause their built-in methods to misbehave by not cooperating with methods overridden by subclasses.

玩了一会儿之后,内置 list 的问题似乎不那么严重了(我尝试在 Python 3.4 中破坏它一段时间,但没有发现非常明显的意外行为),但我仍然想发布一个原则上会发生什么的演示,所以这里有一个 dict 和一个 UserDict:

>>> class MyDict(dict):
...     def __setitem__(self, key, value):
...         super().__setitem__(key, [value])
... 
>>> d = MyDict(a=1)
>>> d
{'a': 1}

>>> class MyUserDict(UserDict):
...     def __setitem__(self, key, value):
...         super().__setitem__(key, [value])
... 
>>> m = MyUserDict(a=1)
>>> m
{'a': [1]}

如您所见,dict 中的 __init__ 方法忽略了覆盖的 __setitem__ 方法,而 __init__我们的 UserDict 方法没有。

关于python - 让一个类表现得像 Python 中的一个列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36688966/

相关文章:

Python Rest客户端api上传文件

c# - 如何在foreach循环中实现通用输入参数属性名称

python - 为什么分数模块中数字字符串(浮点)和浮点实例的结果存在差异?

python - 递归定位包含目标键和值的嵌套字典

python - Feedparser.parse() 'SSL: CERTIFICATE_VERIFY_FAILED'

python - 在 Pandas 中 reshape 数据框

java - 如何获取包含 JSONObject 的列表的大小?

r - 使用 lapply : How to paste object names to file names? 将数据帧列表写入文件

python - 当数字从两位数变为一位数时,如何使屏幕上的字体居中?

python - Numpy/matplotlib - 绘制线性回归会产生错误的斜率