符合Python风格的对象

array和bytes的转换

  - 每个array必须有一个type_code,以此为依据解析底层字节序列

  - array有一个frombytes方法,可以把字节序列按type_code转换成Array

  - bytes构造函数接受一个可迭代对象作为参数,它依次遍历可迭代对象,将每个元素按其本身的数据类型拆成字节

from array import array


def create_bytes():

    type_code = 'f'

    # ord函数返回字符的编码
    print('type_code:',ord(type_code))

    ar = array(type_code,[0.19,0.23])

    # bytes构造函数接受一个可迭代对象作为参数
    # 它依次遍历可迭代对象,将每个元素拆成字节
    # type_code1个字节,float4个字节,一共9个字节
    by = bytes([ord(type_code)]) + bytes(ar)

    print('bytes(len:%d):' % len(by), by)

    return by


def from_bytes(by):

    # 将第一个字节转换为字符
    type_code = chr(by[0])

    # 以后的每4个字节转换为一个float
    # 先用type_code构造一个Array
    arr = array(type_code)
    # 再把字节序列按type_code转换成Array
    arr.frombytes(by[1:])

    print(arr)


bytes = create_bytes()

from_bytes(bytes)

输出:
type_code: 102
bytes(len:9): b'f\\\x8fB>\x1f\x85k>'
array('f', [0.1899999976158142, 0.23000000417232513])

 

classmethod和staticmethod

class Demo:

    @classmethod
    def klassmethod(*args):
        print(args)

    @staticmethod
    def statmethod(*args):
        print(args)


# classmethod自动将类作为第一个参数传入
Demo.klassmethod()
Demo.klassmethod('param')

# staticmethod只是定义在类中的一个普通方法
Demo.statmethod()
Demo.statmethod('param')

输出:
(<class '__main__.Demo'>,)
(<class '__main__.Demo'>, 'param')
()
('param',)

 

对象散列相关方法

  - 首先要保证对象不可变

  - 其次要实现hash和eq方法

class Vector2d:

    def __init__(self,_x,_y):

        self._x = float(_x)
        self._y = float(_y)

    def __iter__(self):

        return (item for item in (self.x,self.y))

    # 用propery装饰器设置只读属性,保持对象的不可变
    @property
    def x(self):

        return self._x

    @property
    def y(self):

        return self._y

    # 使对象可散列
    def __hash__(self):

        return hash(self.x) ^ hash(self.y)

    # 可散列的同时,还要实现相等方法
    def __eq__(self, other):

        return self.x == other.x and self.y == other.y


v1 = Vector2d(3,4)

v2 = Vector2d(3,4)


print(hash(v1),hash(v2),v1==v2)

输出:
7 7 True

 

Python的私有属性

class Dog:

    def __init__(self,name):

        # 如果以__var的形式命名实例属性,Python会把属性名存入实例的__dict__属性中
        # 而且会在前面加上一个下划线和类名
        self.__name = name

dog = Dog('Bob')

print(dog.__dict__)

# 'Dog' object has no attribute '__name'
# print(dog.__name)

print(dog._Dog__name)

输出:
{'_Dog__name': 'Bob'}
Bob

 

使用__slots__类属性

  - 用法

    - 创建__slots__类属性,把值设置为一个属性名称(字符串)构成的可迭代对象

  - 好处:

    - 可以避免使用消耗内存的__dict__属性,从而节约内存

    - 不允许实例动态创建其他的属性

class Vector2d:

    __slots__ = ('_x','_y')

    def __init__(self,_x,_y):

        self._x = float(_x)
        self._y = float(_y)


v2d = Vector2d(1,2)

# 'Vector2d' object has no attribute '__dict__'
# print(v2d.__dict__)

# 'Vector2d' object has no attribute 'z'
# v2d.z = 'z'

 

  - 注意点

    - 如果把 '__dict__' 这个名称添加到__slots__中,实例会在元组中保存各个实例的属性,此外还支持动态创建属性

    - 为了让对象支持弱引用,需要再__slots__中放__weakref__属性

    - 每个子类要定义自己的__slots__属性,继承无效

class Vector2d:

    __slots__ = ('_x','_y','__dict__')

    def __init__(self,_x,_y):

        self._x = float(_x)
        self._y = float(_y)


v2d = Vector2d(1,2)

v2d.z = 'z'

print(v2d.__dict__)

输出:
{'z': 'z'}

 

posted @ 2019-03-18 20:45  StackNeverOverFlow  阅读(150)  评论(0编辑  收藏  举报