python - 同时实现两个内部 Python 类型
问题描述
我正在尝试将函数的返回类型从更改set
为list
. 为了顺利过渡,我们的想法是进行就地弃用并临时返回一个既是 aset
又是a的类型list
。但我不确定是否可以从两种内部 Python 类型派生,因为:
>>> class ListSet(list, set):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: multiple bases have instance lay-out conflict
一般来说,目标是拥有一种行为类似于排序集的类型(我认为它与列表和集合几乎相同)但也适用于类型检查(理想情况下也适用于 MyPy):
thing = class.method_with_updated_return_type()
print(isinstance(thing, set)) # True
print(isinstance(thing, list)) # True
否则我的想法是重写元类的__instancecheck__
方法,ListSet
类似于
class Meta(type):
def __instancecheck__(self, instance):
return isinstance(instance, (set, list))
class ListSet(metaclass=Meta):
# implement all set and list methods
在 Python 中这样的事情可能吗?
解决方案
因此,不,直接继承自set
或 list
将使自定义类的实例返回“True”以进行isinstance
调用。并且有几个原因导致一个类不能同时从两者继承,即使你在本机代码中编写这样一个类,或者用 ctypes 修改它,以便它会返回 True 进行这样的isinstance
检查,结果class 可能会在使用时使您的 Python 解释器崩溃。
另一方面,如果被问及任何类的实例是否是使用这些方法的自定义类的实例,抽象基类和 、__instancecheck__
和方法提供的机制允许回答“真”。也就是说:如果被问到,您的自定义类可以回答任意列表或集合是其自身的一个实例,例如 in - 但不是相反:将始终返回 False。__subclasscheck__
__subclasshook__
register
myobj = set((1,2,3)); isinstance(myobj, MySpecialClass) -> True
isinstance(MySpecialClass(), set)
为了允许类似的机制,推荐的是一种用于prococols的代码,而不是用于特定类的代码。有,任何编写良好的代码应该总是做isinstance(obj, collections.abc.Set)
或collections.abc.Sequence
永远不会isinstance(..., set)
(或list
)。然后任何人都可以将自定义类注册为这些类的子类,测试将是True
:
from collections.abc import MutableSet, Sequence
class MyClass(MutableSet):
# <-NB. don't try to inherit _also_ from Sequence here. See bellow.
# code mandatory methods for MutableSet according to
# https://docs.python.org/3/library/collections.abc.html,
# plus customize all mandadory _and_ derivative methods
# for a mutable sequence, in order to have your
# desired "ordered mutable set" behavior here.
# After the class body, do:
Sequence.register(MyClass)
调用Sequence.register
将注册MyClass
为 Sequence 的虚拟子类,以及任何行为良好的代码,通过 collections.abc.Sequence 实例检查测试协议,或者更好的是,只根据需要使用对象的代码允许不正确的对象在运行时失败,只会工作。如果您可以摆脱任何“isinstance”检查,只需编写“MutableSet”的适当实现即可为您提供一个“有序集”,它可以像您想要的那样工作,而不必担心对对象类型的任意检查。
这一点都不难:你可以只实现所需的方法,初始化一个包含你的类中实际数据 __init__
的列表,更新对 Set 的所有内容修改调用的列表,并在列表上迭代
from collections.abc import MutableSet
class OrderedSet(MutableSet):
def __init__(self, initial=()):
self.data = list()
self.update(initial)
def update(self, items):
for item in items:
self.add(item)
def __contains__(self, item):
return item in self.data
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
def add(self, item):
if item not in self.data:
self.data.append(item)
def discard(self, item):
self.data.remove(item)
def __repr__(self):
return f"OrderedSet({self.data!r})"
但是,如果您无法更改“set”或“list”实例的硬编码测试,那么您无能为力。
推荐阅读
- git - 使用 git filter-branch 进行特定提交
- php - 将字符串变量插入数组
- python - 谷歌 colab 深度学习 python
- python-3.x - 由于大量输入数据导致内存不足错误
- java - Java 批量重启不处理步骤
- autohotkey - 如何在下划线字符后防止 AutoHotkey 热字串?
- android - Android:从服务器下载视频,但如何限制共享和外部应用程序访问,如 Youtube 下载视频。
- azure - 错误 Azure Functions 计时器图
- json - 在 Scala 中解析复杂的 JSON
- c# - 无法访问连接到 WebAPI 的已处置对象应用程序