Python ABC:注册与子类化

发布于 2024-09-12 12:24:45 字数 1588 浏览 2 评论 0原文

(我使用的是 python 2.7)python 文档表明您可以将映射传递到内置字典,它将将该映射复制到新字典中:

http://docs.python.org/library/stdtypes.html#mapping-types-dict

我有一个实现映射 ABC 的类,但它失败了:

import collections
class Mapping(object):
    def __init__(self, dict={}): self.dict=dict
    def __iter__(self): return iter(self.dict)
    def __iter__(self): return iter(self.dict)
    def __len__(self): return len(self.dict)
    def __contains__(self, value): return value in self.dict
    def __getitem__(self, name): return self.dict[name]

m=Mapping({5:5})
dict(m)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: cannot convert dictionary update sequence element #0 to a sequence
collections.Mapping.register(Mapping)
dict(m)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: cannot convert dictionary update sequence element #0 to a sequence

但是,如果我的类子类化了collections.Mapping,那么它就可以正常工作:

import collections
class Mapping(collections.Mapping):
    def __init__(self, dict={}): self.dict=dict
    def __iter__(self): return iter(self.dict)
    def __iter__(self): return iter(self.dict)
    def __len__(self): return len(self.dict)
    def __contains__(self, value): return value in self.dict
    def __getitem__(self, name): return self.dict[name]

m=Mapping({5:5})
dict(m)
# {5: 5}

我认为ABC的全部要点是允许注册与子类化相同(无论如何对于isinstance和issubclass)。那么这是怎么回事?

(I am using python 2.7) The python documentation indicates that you can pass a mapping to the dict builtin and it will copy that mapping into the new dict:

http://docs.python.org/library/stdtypes.html#mapping-types-dict

I have a class that implements the Mapping ABC, but it fails:

import collections
class Mapping(object):
    def __init__(self, dict={}): self.dict=dict
    def __iter__(self): return iter(self.dict)
    def __iter__(self): return iter(self.dict)
    def __len__(self): return len(self.dict)
    def __contains__(self, value): return value in self.dict
    def __getitem__(self, name): return self.dict[name]

m=Mapping({5:5})
dict(m)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: cannot convert dictionary update sequence element #0 to a sequence
collections.Mapping.register(Mapping)
dict(m)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: cannot convert dictionary update sequence element #0 to a sequence

However, if my class subclasses collections.Mapping then it works fine:

import collections
class Mapping(collections.Mapping):
    def __init__(self, dict={}): self.dict=dict
    def __iter__(self): return iter(self.dict)
    def __iter__(self): return iter(self.dict)
    def __len__(self): return len(self.dict)
    def __contains__(self, value): return value in self.dict
    def __getitem__(self, name): return self.dict[name]

m=Mapping({5:5})
dict(m)
# {5: 5}

I thought the whole point of the ABCs was to allow registration to work the same as subclassing (for isinstance and issubclass anyway). So what's up here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

向地狱狂奔 2024-09-19 12:24:45

注册不会为您提供在您定义的方法之上实现的“缺失方法”:事实上,注册对于您正在注册的类型来说是非侵入性的 - 不会添加任何内容,没有任何东西被删除,没有任何东西被改变。它影响isinstanceissubclass检查:仅此而已。

除了您必须自己定义的方法之外,对 ABC 进行子类化可以而且确实为您提供了由 ABC “免费”实现的大量方法。

与旨在丰富类(如子类化)的操作相比,注册等完全非侵入性的操作的语义显然不能相同;所以你对“ABC的全部要点”的理解是不完美的——ABC有两个点,一是通过子类化获得的(“侵入性”),一是通过注册获得的(非侵入性)。

请注意,如果您已经拥有像原始 Mapping 这样的类,则始终可以进行多重继承: class GoogMapping(Mapping, collections.Mapping): ... 将为您提供与直接从 collections.Mapping 继承 Mapping 的结果相同 - 一种新类型,具有collections.Mapping< 添加的所有辅助方法/代码>。

Registration does not give you the "missing methods" implemented on top of those you define: in fact, registration is non-invasive with respect to the type you're registering -- nothing gets added to it, nothing gets removed, nothing gets altered. It only affects isinstance and issubclass checks: nothing more, nothing less.

Subclassing an ABC can and does give you plenty of methods implemented "for free" by the ABC on top of those you're having to define yourself.

The semantics of an operation that's totally non-invasive like registering, compared to those of an operation that's intended to enrich a class, like subclassing, obviously cannot be identical; so your understanding of "the whole point of the ABCs" is imperfect -- ABCs have two points, one obtained by subclassing ("invasive"), one by registering (non-invasive).

Note that you can always multiply-inherit if you already have a class like your original Mapping: class GoogMapping(Mapping, collections.Mapping): ... will give you the same results as inheriting Mapping directly from collections.Mapping -- a new type with all the auxiliary methods added by collections.Mapping.

十级心震 2024-09-19 12:24:45

啊,看起来 dict() 正在寻找 key 方法...它不使用 ABC。

Ah, looks like dict() is looking for the keys method... It doesn't use the ABCs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文