符合python风格的对象

image-20200407123042829

image-20200407123103257

❶ klassmeth 返回全部位置参数。 ❷ statmeth 也是。 ❸ 不管怎样调用 Demo.klassmeth, 它的第一个参数始终是 Demo 类。 ❹ Demo.statmeth 的行为与普通的函数相似。

classmethod 装饰器非常有用, 但是我从未见过不得不用staticmethod 的情况。 如果想定义不需要与类交互的函数, 那么在模块中定义就好了。

可散列的vector

按照定义, 目前 Vector2d 实例是不可散列的, 因此不能放入集合
(set) 中:
>>> v1 = Vector2d(3, 4)
>>> hash(v1)
Traceback (most recent call last):
...
TypeError: unhashable type: 'Vector2d'
>>> set([v1])
Traceback (most recent call last):
...
TypeError: unhashable type: 'Vector2d'
为了把 Vector2d 实例变成可散列的, 必须使用 __hash__ 方法(还需
__eq__ 方法, 前面已经实现了) 此外, 还要让向量不可变, 详情
参见第 3 章的附注栏“什么是可散列的数据类型”。
目前, 我们可以为分量赋新值, v1.x = 7Vector2d 类的代码并
不阻止这么做。 我们想要的行为是这样的:
>>> v1.x, v1.y
(3.0, 4.0)
>>> v1.x = 7
Traceback (most recent call last):
...
AttributeError: can't set attribute
为此, 我们要把 x y 分量设为只读特性, 如示例 9-7 所示。
示例 9-7 vector2d_v3.py: 这里只给出了让 Vector2d 不可变的代
码, 完整的代码清单在示例 9-9
class Vector2d:
   typecode = 'd'
   def __init__(self, x, y):
       self.__x = float(x) ➊self.__y = float(y)
   @property
   def x(self):
       return self.__x
   @property
   def y(self):
       return self.__y
   def __iter__(self):
       return (i for i in (self.x, self.y))
# 下面是其他方法(排版需要, 省略了)
使用两个前导下划线(尾部没有下划线, 或者有一个下划线)
属性标记为私有的。
根据本章开头引用的那句话, 这不符合 Ian Bicking 的建议。 私有属性的优缺点参见后面的 9.7
节。
@property 装饰器把读值方法标记为特性。
读值方法与公开属性同名, 都是 x。
直接返回 self.__x。
以同样的方式处理 y 特性。
需要读取 x y 分量的方法可以保持不变, 通过 self.x self.y
读取公开特性, 而不必读取私有属性, 因此上述代码清单省略了这个类
的其他代码。

然后重写hash

# 在Vector2d类中定义
def __hash__(self):
return hash(self.x) ^ hash(self.y)
添加 __hash__ 方法之后, 向量变成可散列的了:
>>> v1 = Vector2d(3, 4)
>>> v2 = Vector2d(3.1, 4.2)
>>> hash(v1), hash(v2)
(7, 384307168202284039)
>>> set([v1, v2])
{Vector2d(3.1, 4.2), Vector2d(3.0, 4.0)}

Python的私有属性和“受保护的”属性

python 不像java 可以用private定义私有属性++

但是Python 有个简单的机制, 能避免子类意外覆盖“私有”属性。 举个例子。 有人编写了一个名为 Dog 的类, 这个类的内部用到了 mood 实例属性, 但是没有将其开放。 现在, 你创建了 Dog 类的子 类: Beagle。 如果你在毫不知情的情况下又创建了名为 mood 的实例属 性, 那么在继承的方法中就会把 Dog 类的 mood 属性覆盖掉。 这是个难 以调试的问题。

为了避免这种情况, 如果以 __ mood 的形式(两个前导下划线, 尾部没 有或最多有一个下划线) 命名实例属性, Python 会把属性名存入实例的 _ dict__ 属性中, 而且会在前面加上一个下划线和类名。 因此, 对 Dog 类来说, __ mood 会变成 _ Dog __ mood; 对 Beagle 类来说, 会变成 _Beagle__mood。 这个语言特性叫名称改写

类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在dict里的

总结:

  1) 内置的数据类型没有 __ dict__属性

  2) 每个类有自己的 __ dict属性,就算存着继承关系,父类的 dict__ 并不会影响子类的__ dict__

  3) 对象也有自己的__ dict属性, 存储self.xxx 信息,父子类对象公用 dict__

image-20200407134334457

image-20200407134501701

slots 的问题 总之, 如果使用得当, slots 能显著节省内存, 不过有几点要注 意。 每个子类都要定义 slots 属性, 因为解释器会忽略继承的 slots 属性。 实例只能拥有 slots 中列出的属性, 除非把 'dict' 加 slots 中(这样做就失去了节省内存的功效) 。 如果不把 'weakref' 加入 slots, 实例就不能作为弱引 用的目标。

抽象方法使用 @abstractmethod 装饰器标记

 

posted on 2020-09-25 13:43  Handso  阅读(192)  评论(0编辑  收藏  举报

导航