前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《流畅的Python》第九章学习笔记

《流畅的Python》第九章学习笔记

作者头像
zx钟
发布2021-01-07 17:45:39
3070
发布2021-01-07 17:45:39
举报
文章被收录于专栏:测试游记

要构建符合Python风格的对象,就要观察真正的Python对象的行为。

对象表示形式

获取对象表示形式的标准方法

repr()

以便于开发者理解的方式返回对象的字符串表示形式

str()

以便于用户理解的方式返回对象的字符串表示形式

classmethod与staticmethod

classmethod(非常有用)

定义 操作类,而不是操作实例的方法。

最常见的用途是定义备选构造方法

staticmethod(不是特别有用)

静态方法就是普通的类,只是碰巧在类的定义体中,而不是在模块层定义

虽然函数不处理类,但是函数的功能与类紧密相关,因此把它放在近处。

可散列

只需要正确事项__hash____eq__方法即可。

实例的散列值绝不应该变化。

书中Vector2d例子

代码语言:javascript
复制
# -*- coding: utf-8 -*-
from array import array
import math


class Vector2d:
    typecode = 'd'  # 类属性

    def __init__(self, x, y):
        """
        将x与y转换为浮点数,尽早捕获错误
        :param x:
        :param 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))

    def __repr__(self):
        class_name = type(self).__name__
        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 math.hypot(self.x, self.y)

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

    def __format__(self, format_spec=''):
        if format_spec.endswith('p'):
            format_spec = format_spec[:-1]
            coords = (abs(self), self.angle())
            outer_fmt = '<{}, {}>'
        else:
            coords = self
            outer_fmt = '({}, {})'
        components = (format(c, format_spec) for c in coords)
        return outer_fmt.format(*components)

    def __hash__(self):
        return hash(self.x) ^ hash(self.y)

    def angle(self):
        """
        计算函数角度
        :return:
        """
        return math.atan2(self.y, self.x)

    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0])
        memv = memoryview(octets[1:]).cast(typecode)
        return cls(*memv)


if __name__ == '__main__':
    v1 = Vector2d(3, 4)
    print(v1.x, v1.y)  # 3.0 4.0
    x, y = v1
    print(x, y)  # 3.0 4.0
    print(v1)  # (3.0, 4.0)
    v1_clone = eval(repr(v1))
    print(v1 == v1_clone)  # True
    octets = bytes(v1)
    print(octets)  # b'd\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00\x00\x00\x00\x10@'
    print(abs(v1))  # 5.0
    print(bool(v1))  # True
    print(bool(Vector2d(0, 0)))  # False

    v1_clone = Vector2d.frombytes(bytes(v1))
    print(v1_clone)  # (3.0, 4.0)
    print(v1 == v1_clone)  # True

    print(format(v1))  # (3.0, 4.0)
    print(format(v1, '.2f'))  # (3.00, 4.00)
    print(format(v1, '.3e'))  # (3.000e+00, 4.000e+00)

    print(Vector2d(0, 0).angle())  # 0.0
    print(Vector2d(1, 0).angle())  # 0.0
    epsilon = 10 ** -8
    print(abs(Vector2d(0, 1).angle() - math.pi / 2) < epsilon)  # True
    print(abs(Vector2d(1, 1).angle() - math.pi / 4) < epsilon)  # True

    print(format(Vector2d(1, 1), 'p'))  # <1.4142135623730951, 0.7853981633974483>
    print(format(Vector2d(1, 1), '.3ep'))  # <1.414e+00, 7.854e-01>
    print(format(Vector2d(1, 1), '0.5fp'))  # <1.41421, 0.78540>

    v1 = Vector2d(3, 4)
    v2 = Vector2d(3.1, 4.2)
    print(hash(v1))  # 7
    print(hash(v2))  # 384307168202284039
    print(len(set([v1, v2])))  # 2

私有属性

使用双下划线开头的属性会存入到__dict__属性中,并且会在前面加上一个下划线和类名

代码语言:javascript
复制
class A():
    def __init__(self, x, y):
        self.__x = x
        self.__y = y


if __name__ == '__main__':
    a = A(1,2)
    print(a.__dict__) # {'_A__x': 1, '_A__y': 2}

目的是为了避免意外访问,不能防止故意做错事。

单下划线开头的属性不会有上述变化,但是规定也是将这种变量规定为私有属性。

当使用from xxx import *导入的时候,下划线开头的名称不会被导入

使用`slots`类属性节省空间

在类中定义__slots__的目的就是告诉解释器:这个类中的所有实例属性都在这儿了。

实例中不能再有__slots__中所列名称之外的其他属性。

__slots__是用于优化的,不是为了约束程序员。

问题

  1. 每个子类都需要定义slots__`,因为解释器会忽略集成的`__slots属性
  2. 实例只能拥有slots__`中列出的属性,除非把`_dict_`加入`__slots中,不过这样就失去了节省内存的功效
  3. 如果不把weakref__`加入`__slots,实例就不能作为弱引用的目标。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 测试游记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 对象表示形式
    • repr()
      • str()
      • classmethod与staticmethod
        • classmethod(非常有用)
          • staticmethod(不是特别有用)
          • 可散列
          • 书中Vector2d例子
          • 私有属性
          • 使用`slots`类属性节省空间
            • 问题
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档