第9章符合python风格的对象

越努力, 就会越幸运.加油!!!


9.1 对象的表示形式

自定义类的实现一个二维的向量的方法:

from array import array
import math

class Vector2d:
    """实现一个二维的向量"""
    typecode = 'd'

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

    def __iter__(self):
        """把vector2d变成是一个可迭代的对象, 这样才能进行拆包的计算"""
        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)])  # ord 返回的是一个unicode类型的字节

    def __eq__(self, other):
        """只有当两个对象都是vector2d的时候, 才能进行比较"""
        return tuple(self) == tuple(other)

    def __abs__(self):
        return math.hypot(self.x, self.y)  # hypot 就是计算 x*2 + y*2的结果

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

    def __format__(self, fmt_spec=""):
        """自定义类的format格式的形式, 通过实现__format__的形式来控制类的自定义的格式化的结果"""
        components = (format(c, fmt_spec) for c in self)
        return "({}, {})".format(*components)

获取对象字符串形式的方法;
1. repr()
便于开发者的角度去理解的方式返回对象的字符串的表示形式
2. str()
采用用户便于理解的形式来返回对象的字符串的形式
函数和内置函数的调用关系
1. print 函数会调用str 函数
2. bytes 函数会调用bytes 方法,生成实例的二进制表示形式。
3. abs 函数会调用abs 方法
4. bool 函数会调用bool 方法
5. 使用 type(object).__name__ 可以获取到对象的类型的名称
6. object.__dict__ 可以获取到对象的属性等信息, class.__dict__ 可以获取到所有的这个类的属性, 和方法
7. 如果在一个类中, 重写了python中的method方法的时候, 在使用内置函数的时候, 就会自动的去调用在本类中重写的的方法, 来进行返回的值

9.4 classmethod 与 staticmethod

classmethod 定义操作类, 而不是像对象的时候, 传入的是对象的self 示例, classmethod改变了调用的方式, 第一个参数是类本身, 而不是示例.classmethod最常见的用途是定义备选构造方法

如果需要的method中使用的是类变量的话, 就需要使用的是classmethdo 装饰器, staticmethod 其实只是为了, 把这个方法归入到类中来进行使用, 其中的参数, 没有类变量和示例变量

格式化显示

内置的format()函数, 和 str.format()方法把各个类型的格式化方式委托给响应的__format__(format_spec)的方法, format_spec 就是格式说明符, 它是:
1. format(mg_obj, format_spec)的第二个参数, 或者
2. str.format()方法的格式字符串, {}里代换字段中冒号后买呢的部分


b1 = 1/2.34

b1
Out[2]: 0.4273504273504274

format(b1, '0.4f')
Out[3]: '0.4274'

"{rate:0.2f}".format(rate=b1)  # 使用制定的字段, 来制定需要格式化的部分
Out[4]: '0.43'
# 上面的字符串中包含了两部分, 第一是指定的和后面的字段名称, 第二个是格式说明符


format(43, "b")
Out[6]: '101011'

format(2/3, ".1%")
Out[7]: '66.7%'

使用format格式化时间和日期

from datetime import datetime

now = datetime.now()

now
Out[10]: datetime.datetime(2018, 3, 28, 14, 16, 39, 107306)

format(now, "%H:%M:%S")
Out[11]: '14:16:39'
format(now, "%Y-%M-%d")
Out[15]: '2018-16-28'

如果类中没有定义format方法, 从object继承的方法会返回str(my_object).所以说如果想要在自定义的类中实现格式话的效果, 就需要使用重写format 方法来控制显示

然而,如果传入格式说明符,object.format 方法会抛出TypeError:

>>> format(v1, '.3f')
Traceback (most recent call last):

TypeError: non-empty format string passed to object.__format__

9.6可散列的二维向量

实现可散列的vector2d , 按照定义目前的vector2d示例是不可散列的, 因此不能直接的放入到集合中的\

如果需要实现, 可散列的类型, 需要实现__hash____eq__ 方法, 示例的散列值绝对不应该变化的, 所以需要使用属性的时候, 是需要保证属性的只读属性

__int____float__ 可以分别被int() 和float() 构造函数调用, 以便于在某些情况下用于强制的类型转换.

9.7 python的私有属性和”受保护的属性的使用”“

python 在实现私有属性的时候才用__mood的形式.两个前导下划线,尾部没有或最多有一个下划
线)命名实例属性,Python 会把属性名存入实例的__dict__ 属性中,而且会在前面加上一
个下划线和类名。因此,对Dog 类来说,__mood 会变成_Dog__mood;对Beagle 类来说,会
变成_Beagle__mood。这个语言特性叫名称改写

dog.__dict__
{'_Dog__name': 'haha'}

python 约定使用单下划线self._name来处理私有的属性, python解释器是不会对但下划线做出修改的, 这样也不会再类的外部就进行访问. 遵循使用一个下划线标对象的私有属性是很容易的, 就像最受使用全部的大写字母编写常量那样容易.

9.8使用solts类属性节省空间

默认情况下,Python 在各个实例中名为dict 的字典里存储实例属性。如3.9.3 节所述,
为了使用底层的散列表提升访问速度,字典会消耗大量内存。如果要处理数百万个属性不
多的实例,通过slots 类属性,能节省大量内存,方法是让解释器在元组中存储实例
属性,而不用字典。

继承自超类的__slots__ 属性没有效果。Python 只会使用各个类中定义的__slots__ 属性。

定义slots 的方式是,创建一个类属性,使用slots 这个名字,并把它的值设为
一个字符串构成的可迭代对象,其中各个元素表示各个实例属性。我喜欢使用元组,因为
这样定义的slots 中所含的信息不会变化.

class Vector2d:
    """使用__solts__来限制类中属性的存储位置"""
    __slots__ = ("__x", "__y")
    typecode = 'd'

# 如果使用了__solts__来固定类的属性的话, 这样就不会再存在 object.__dict__ 这个内置的属性了, 会把属性的值, 存入到一个类似的元组中的

在类中定义slots 属性的目的是告诉解释器:“这个类中的所有实例属性都在这儿
了!”这样,Python 会在各个实例中使用类似元组的结构存储实例变量,从而避免使用消
耗内存的dict 属性。如果有数百万个实例同时活动,这样做能节省大量内

此外,还有一个实例属性可能需要注意,即weakref 属性,为了让对象支持弱引用
(参见8.6 节),必须有这个属性。用户定义的类中默认就有weakref 属性。可是,如
果类中定义了slots 属性,而且想把实例作为弱引用的目标,那么要把’weakref
添加到slots 中。

综上,slots 属性有些需要注意的地方,而且不能滥用,不能使用它限制用户能赋值
的属性。处理列表数据时slots 属性最有用,例如模式固定的数据库记录,以及特大型数据集。然而,如果你经常处理大量数据,一定要了解一下NumPy

slots的问题
总之,如果使用得当,slots 能显著节省内存,不过有几点要注意。
• 每个子类都要定义slots 属性,因为解释器会忽略继承的slots 属性。
• 实例只能拥有slots 中列出的属性,除非把’dict’ 加入slots 中(这样做
就失去了节省内存的功效)。
• 如果不把’weakref’ 加入slots,实例就不能作为弱引用的目标。
如果你的程序不用处理数百万个实例,或许不值得费劲去创建不寻常的类,那就禁止它创
建动态属性或者不支持弱引用。与其他优化措施一样,仅当权衡当下的需求并仔细搜集资
料后证明确实有必要时,才应该使用slots 属性

你可能感兴趣的:(流畅的python)