Python ABC:注册与子类化
(我使用的是 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
注册不会为您提供在您定义的方法之上实现的“缺失方法”:事实上,注册对于您正在注册的类型来说是非侵入性的 - 不会添加任何内容,没有任何东西被删除,没有任何东西被改变。它仅影响
isinstance
和issubclass
检查:仅此而已。除了您必须自己定义的方法之外,对 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
andissubclass
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 inheritingMapping
directly fromcollections.Mapping
-- a new type with all the auxiliary methods added bycollections.Mapping
.啊,看起来 dict() 正在寻找 key 方法...它不使用 ABC。
Ah, looks like dict() is looking for the keys method... It doesn't use the ABCs.