解决Python中abc.Sequence、abc.Hashable、list之间的继承矛盾
Posted
技术标签:
【中文标题】解决Python中abc.Sequence、abc.Hashable、list之间的继承矛盾【英文标题】:Solving inheritance contradictions among abc.Sequence, abc.Hashable and list in Python 【发布时间】:2019-09-23 15:50:20 【问题描述】:我使用的是 3.6.3 版
我正在研究Pythoncollections.abc
的类间继承关系。我在list
、Sequence
和Hashable
之间发现了一些矛盾的继承关系
如您所知,
1、Sequence
继承Hashable
类和
2. list
继承Sequence
from collections import Sequence, Hashable
issubclass(Sequence, Hashable) # 1.
issubclass(list, Sequence) # 2.
True
True
由此,您可能会认为 list
在概念上也继承了 Hashable
。
但是 list
是可变的,它不会继承 Hashable
(意味着'你不能'hash(some_list)')
issubclass(list, Hashable)
False
我认为这种继承是矛盾的。我完全理解list
是可变的,因为我已经使用了数百次list
,但是继承关系图不支持这个概念。我错了什么或遗漏了什么?
我等待您的建议。谢谢。
【问题讨论】:
你看过这个博客吗:naftaliharris.com/blog/python-subclass-intransitivity?它看起来很不错,这里引用了一句,“...Iterable 是 Hashable 的“子类”——说真的,因为 Iterable 具有从对象继承的__hash__
方法”。
Sequence
有一个__hash__
方法,但是根据docs.python.org/3.6/library/…,Sequence
不继承自Hashable
。 (不是答案,只是观察。)
@SuperShoot 感谢您的参考。我非常喜欢这种方法:在 Python 中获取所有类并测试所有三元组依赖项检查。我想我应该稍后再深入研究metaclass
。 :)
我也将那本书添加到我的阅读清单中。感谢您的出色 Q 并祝您在 Python 学习中一切顺利。
【参考方案1】:
所以它实际上是一个有趣的设计特性,但 Python 子类实际上不需要是可传递的。 Google 定义的传递性:
"如果一个特征适用于序列的连续成员之间,它也必须适用于按顺序排列的任何两个成员之间。例如,如果 A 大于 B,并且 B 大于 C,则 A 大于C。”
对于继承是传递性的语言,例如Java,如果B
继承A
和C
继承B
,那么C
必须继承A
。 C
的传递超类集为A
、B
和Object
,直接超类为B
。
在 Python 中,我们背离了这个概念。正如您所指出的,Sequence
是 Hashable
,list
是 Sequence
,但 list
不是 Hashable
。事实上,list 并没有直接继承任何东西(除了 object
每个 python 类都继承)。
# from the PyCharm generated stubs
class list(object):
...
在 Python 中,您可以使用元类实用程序中的 __subclasscheck__
或 __subclasshook__
来使内置方法 issubclass
做一些有趣的事情。元类是一种高级语言功能,用于修改类操作的基本规则(修改issubclass
的工作方式就是一个很好的例子)。在抽象基类元类ABCMeta
中,__subclasscheck__
方法将在类上调用__subclasshook__
方法(如果已定义)。您可以阅读great answer about the uses here。
某些ABCMeta
类如Hashable
实现__subclasshook__
不是检查继承树,而是检查方法是否存在。这很有帮助,这样就不必在您创建的每个类定义中都包含常见的合同。
对于这种情况,为了成为Hashable
,您需要定义__hash__
。但是,Python 声明不要在 List 上散列,因为它是可变的,因此在此类中特别省略了它。
class Hashable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __hash__(self):
return 0
@classmethod
def __subclasshook__(cls, C):
if cls is Hashable:
return _check_methods(C, "__hash__")
return NotImplemented
class list(object):
...
__hash__ = None
【讨论】:
class list(object):
不会出现在 list
类的实际定义中的任何位置。 class list(object)
出现在 help(list)
输出中,它可能出现在 PyCharm 假源代码或类似的东西中,但 actual class definition 在 C 中。
@user2357112 啊,谢谢,好点,我会把它加进去。虽然列表只继承对象,但它仍然是正确的;由于是一个 python 对象。
谢谢我的朋友。非常有趣的是 Python 类并不简单地遵循概念继承树。但是你能告诉我transitive
的含义吗?我不会说英语,所以这让我有点困惑。
@flakes 谢谢,您编辑的答案更清晰。但它也给我带来了更多的问题。为什么你的代码实现subclasshook
,而不是subclasscheck
,什么是_check_methods
?我明白了,很感激。
@flakes 请知道,我非常感谢您为做出无错误和更清晰的答案所做的努力。我的 Python 得到了改进。非常感谢:)以上是关于解决Python中abc.Sequence、abc.Hashable、list之间的继承矛盾的主要内容,如果未能解决你的问题,请参考以下文章
python定义接口继承类invalid syntax解决办法
在MySQL中出现Unknown column 'abc' in 'field list'怎么解决?