Fluent Python

符合 Python 风格的对象

2018-01-02  本文已影响12人  一块大番薯

对象表现形式

向量类

from array import array  # 实例与字节序列转换时使用
from math import hypot  # 计算模

class Vector2d:
    typecode = 'd'  # 实例与字节序列转换时使用

    def __init__(self, x, y):
        self.x = float(x)  # 尽早捕捉错误,以防构建实例时传入错误参数
        self.y = float(y)

    def __iter__(self):  # 实现拆包
        return (i for i in (self.x, self.y))

    def __repr__(self):
        class_name = type(self).__name__
        # {!r} 获取各个分量
        return '{}({!r}, {!r})'.format(class_name, *self) 

    def __str__(self):  # 打印实例时调用
        return str(tuple(self))

    def __bytes__(self):
        return bytes([ord(self.typecode)]) + bytes(array(self.typecode, self)) 

    def __eq__(self, other):
        return tuple(self) == tuple(other)

    def __abs__(self):
        return hypot(*self)

    def __bool__(self):
        return bool(abs(self))
Vector2d

calssmethod 与 staticmethod

classmethod 与 staticmethod

格式化显示

格式化显示
def angle(self):
    return atan2(self.y, self.x)  # math.atan2

def __format__(self, fmt_spec=''):
    if fmt_spec.endswith('p'):
        fmt_spec = fmt_spec[:-1]  # 去掉最后的p
        coords = (abs(self), self.angle())
        outer_fmt = '<{}, {}>'
    else:
        coords = self
        outer_fmt = '({}, {})'

    components = (format(c, fmt_spec) for c in coords)
    return outer_fmt.format(*components)
自定义格式规范微语言

可散列的 Vector2d

自定义的类的实例默认都是不可散列的,除非实现了 _hash_ 方法

默认不可散列
现在实现 _hash_ 方法:
def __hash__(self):
    return hash(self.x) ^ hash(self.y)
实现可散列
虽然可散列了,但是对象还是可变的

下面实现对象不可变:

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
不可变

私有属性

使用 _slots_ 类属性节省空间

实例属性存储在 _dict_字典中。

__dict__
但是字典为了底层的散列表提高访问速度,会消耗大量内存。
如果要处理数以百万的实例,而这些实例属性不多,则可以考虑 _slots_ 节省内存
class Vector2d:
    __slots__ = ('__x', '__y')

把所有的属性都放到类属性 _slots_

覆盖类属性

typecode 设为 f,代表 4 字节单精度浮点数;设为 d,代表 8 字节双精度浮点数。

上一篇 下一篇

猜你喜欢

热点阅读