为什么从抽象基类继承时,Python2和Python3中的插槽行为不同

为什么从抽象基类继承时,Python2和Python3中的插槽行为不同,python,python-3.x,python-2.x,abstract-base-class,Python,Python 3.x,Python 2.x,Abstract Base Class,我创建了下面的类来以内存高效的方式存储平面上的可变点-我需要一个可变的等价物namedtuple('Point','xy')。由于实例字典很大,我想我应该选择\uuuuuuuuuuuuuuu: from collections import Sequence class Point(Sequence): __slots__ = ('x', 'y') def __init__(self, x=0, y=0): self.x = x self.y

我创建了下面的类来以内存高效的方式存储平面上的可变点-我需要一个可变的等价物
namedtuple('Point','xy')
。由于实例字典很大,我想我应该选择
\uuuuuuuuuuuuuuu

from collections import Sequence

class Point(Sequence):
    __slots__ = ('x', 'y')

    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __getitem__(self, item):
        return getattr(self, self.__slots__[item])

    def __setitem__(self, item, value):
        return setattr(self, self.__slots__[item], value)

    def __repr__(self):
        return 'Point(x=%r, y=%r)' % (self.x, self.y)

    def __len__(self):
        return 2
在Python 3上测试时,一切似乎都正常:

>>> pt = Point(12, 42)
>>> pt[0], pt.y
(12, 42)
>>> pt.x = 5
>>> pt
Point(x=5, y=42)
>>> pt.z = 6
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'z'

为什么会这样,为什么Python2和Python3之间存在差异?

Python2数据模型说:

  • 当从没有
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    的类继承时,该类的
    \uuuuuuuuuuuuuuuuu
    属性将始终是可访问的,因此子类中的
    \uuuuuuuuuuuuuuuuuuuuuuu
这就是这里正在发生的事情。在Python2中,
集合
模块中的抽象基类根本没有
\uuuuu插槽

>>> from collections import Sequence
>>> Sequence.__slots__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Sequence' has no attribute '__slots__'

因此,在Python2中,您不能从
集合
基类继承,同时使用
\uuuu插槽
进行内存高效存储


然而,请注意,即使索赔文件

这些ABC允许我们询问类或实例是否提供特定功能,例如:

size = None
if isinstance(myvar, collections.Sized):
    size = len(myvar)
);简单地实现
序列所需的所有方法不会使类的实例通过
isinstance
检查

原因是该类没有;如果没有它,则参考父类
\uuuuu子类hook\uuuu
;在这种情况下;如果针对类测试的
大小不准确,则返回
NotImplemented

另一方面,人们无法通过魔法方法来区分映射类型和序列类型,因为它们都可以拥有完全相同的魔法方法-集合的

但是,您仍然不需要从
Sequence
继承以使
isinstance(点,序列)
返回
True
。在下面的示例中,
是相同的,除了在Python 2上从
对象
而不是从
序列
派生之外:

>>> pt = Point(12, 42)
>>> pt.z = 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'z'
>>> isinstance(pt, Sequence)
False
>>> Sequence.register(pt)
>>> isinstance(pt, Sequence)
True
>pt=点(12,42)
>>>第z部分=5
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:“点”对象没有属性“z”
>>>isinstance(pt,序列)
假的
>>>顺序寄存器(pt)
>>>isinstance(pt,序列)
真的
您可以将任何类注册为抽象基类的子类,以进行
isinstance
检查;在额外的混合方法中,您实际上只需要实现
count
index
;其他功能将由Python运行时填充

size = None
if isinstance(myvar, collections.Sized):
    size = len(myvar)
>>> pt = Point(12, 42)
>>> pt.z = 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'z'
>>> isinstance(pt, Sequence)
False
>>> Sequence.register(pt)
>>> isinstance(pt, Sequence)
True