Skip to content

Fluent Python读书笔记(八)

18965050 edited this page Jul 18, 2017 · 3 revisions

Pythonic对象

对象表现(__repr()____str()__ )

除了这两个特殊函数之外, 还有 __bytes()____format()__. __repr()__,__str()____format()__应该返回unicode字符串; __bytes()__返回字节序列

__format()__用于format()函数的调用. format标识符用在两个地方

  • format(my_obj, format_spec)函数的第二个参数
  • str.format()函数中{}类的参数

如果一个类没有定义__format()__方法, 则会使用__str()__方法替代. 但如果要使用format标识符, 则一定要定义__format()__方法

classmethod和staticmethod

classmethod的第一个参数为cls, 一般用于对构造函数的改造或初始化. staticmethod类似于模块中的普通函数, 只不过在类中定义.其第一个参数不要求为self或cls

让类属性变成只读属性

使用@property装饰器. **注意, 根据Python Cookbook说明, @property装饰器是个类装饰器, 包含getter(),setter()和deleter()**三个方法.

from array import array
import math

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))

    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 __hash__(self):
        return hash(self.x) ^ hash(self.y)

    def __abs__(self):
        return math.hypot(self.x, self.y)

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

    def angle(self):
        return math.atan2(self.y, self.x)

    def __format__(self, fmt_spec=''):
        if fmt_spec.endswith('p'):
            fmt_spec = fmt_spec[:-1]
            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)

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

private和protect属性

Python不像Java一样,有严格的私有或保护属性. python规定以__(两个下划线)开头的属性是私有属性, 会转变成_<className>__<attr>的形式保存在__dict__属性中.

_(单个下划线)开头的变量在python中没有特殊的处理, 这只是一个使用惯例, 表示保护变量.

__slots__

默认情况下, python对于实例的属性存放在对象内部的__dict__属性中,dict内部含有稀疏矩阵的哈希表. 因此对于大量实例情况下会非常占用内存空间. 这种情况下, 我们就可以使用__slot__. 当定义了slots后,slots中定义的变量变成了类的描述符,相当于java,c++中的成员变量声明,类的实例只能拥有这些个变量,而不再有dict,因此也就不能再增加新的变量

__slots__也有些使用限制:

  • __slots__不继承, 必须在每个需要的类中作为类变量定义

  • 不允许不在__slot__中的实例属性存在.

     class A:
         __slots__=['name']
         def __init__(self):
             self.name='js'
             self.age=22
     a=A()				#报错. age不在__slots__中存在

    也可以把__dict__存放在__slots__中,这样就可以定义动态属性了

     class A:
       __slots__=('name','city','__dict__')		#将__dict__放入__slots__中
       def __init__(self):
         self.name='js'
         self.age=22		#可以定义age实例属性了. 
     a=A()
  • 除非定义__weakref__()方法, 否则对象不能作为weakref引用对象, 因为定义__slot__后也取消了__weakref__的生成