Ant*_*ala 2 python python-2.x abstract-base-class python-3.x
我创建了以下类,以一种以内存效率的方式在平面上存储可变点 - 我需要一个可变的等价物namedtuple('Point', 'x y').由于实例字典很大,我想我会选择__slots__:
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
Run Code Online (Sandbox Code Playgroud)
在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'
Run Code Online (Sandbox Code Playgroud)
但是在Python 2上,我可以设置属性,z即使它不在插槽中:
>>> pt = Point(12, 42)
>>> pt.z = 5
>>> pt.z
5
>>> pt.__slots__
('x', 'y')
>>> pt.__dict__
{'z': 5}
Run Code Online (Sandbox Code Playgroud)
为什么会这样,为什么Python 2和Python 3之间存在差异?
Python 2数据模型说明如下__slots__:
- 从没有继承的类继承时,该类
__slots__的__dict__属性将始终可访问,因此__slots__子类中的定义毫无意义.
这就是这里发生的事情.在Python 2中,collections模块中的抽象基类根本没有__slots__:
>>> 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__'
Run Code Online (Sandbox Code Playgroud)
这被报告为CPython问题跟踪器中的问题11333,并在Python 3.3中得到修复.
在Python 3.3+中,Sequence抽象基类现在已__slots__设置为空元组:
>>> from collections import Sequence
>>> Sequence.__slots__
()
Run Code Online (Sandbox Code Playgroud)
因此,在Python 2中,您无法从collections基类继承并同时具有内存高效存储__slots__.
但请注意,即使有关collections抽象基类的文档声明了这一点
这些ABC允许我们询问类或实例是否提供特定功能,例如:
Run Code Online (Sandbox Code Playgroud)size = None if isinstance(myvar, collections.Sized): size = len(myvar)
事实并非如此Sequence ; 简单地实现所需的所有方法Sequence不会使您的类的实例通过isinstance检查.
原因是Sequence班级没有__subclasshook__; 在没有的情况下,__subclasshook__会咨询家长班; 在这种情况下Sized.__subclasshook__; NotImplemented如果被测试的类不完全正确 ,则返回Sized.
另一方面,人们无法通过魔法方法区分映射类型和序列类型,因为它们都可以具有完全相同的魔术方法 - collections.OrderedDict具有a的所有魔术方法Sequence,包括__reversed__方法,但它不是一个序列.
但是,您仍然不需要继承Sequence来isinstance(Point, Sequence)返回True.在下面的例子中,Point是相同的,除了衍生自object代替Sequence,关于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
Run Code Online (Sandbox Code Playgroud)
您可以将任何类注册为抽象基类的子类以进行isinstance检查; 和额外的混合方法,你真的只需要实现count和index; 其他人的功能将由Python运行时填充.
| 归档时间: |
|
| 查看次数: |
446 次 |
| 最近记录: |