python中forward_符合python风格的对象

python自带的对象拥有很多有趣的行为,用户自己定义的类对象也可以实现跟python对象相同的行为。

对象的表示形式

python关于对象的表示提供了两种形式:

repr()

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

str()

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

也正是对象的__repr__和__str__两个特殊方法为repr()和str()提供支持。另外还有两个方法,__bytes__和__format__。__bytes__方法跟__str__类似:bytes()函数调用它获取对象的字节序列表示形式;__format_-方法会被内置的format()函数和str.format()方法调用。

向量类

自己定义一个Vector2d类,我们期望他能有下面的表现形式。

1 >>> v1 = Vector2d(3, 4)2 >>> print(v1.x, v1.y)3 3.0 4.0

4 >>> x, y =v15 >>>x, y6 (3.0, 4.0)7 >>>v18 Vector2d(3.0, 4.0)9 >>> v2 =eval(repr(v1))10 >>> v1 ==v211 True12 >>> print(v1)13 (3.0, 4.0)14 >>> octets =bytes(v1)15 >>>octets16 b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'

17 >>>abs(v1)18 5.0

19 >>>bool(v1), bool(Vector2d(0, 0))20 (True, False)

实现代码如下:

1 importmath2 from array importarray3 classVector2d:4 """

5 自定义一个二维向量类6 """

7 typecode = 'd'

8 def __init__(self, x, y):9 self.x =x10 self.y =y11

12 def __iter__(self):13 return (i for i in(self.x, self.y))14

15 def __repr__(self):16 return '{}({!r}, {!r})'.format(type(self).__name__, self.x, self.y)17

18 def __str__(self):19 return str(tuple(self)) #已经实现了__iter__方法,self实例是可迭代对象

20

21 def __eq__(self, other):22 return tuple(self) ==tuple(other)23

24 def __abs__(self):25 returnmath.hypot(self.x, self.y)26

27 def __bool__(self):28 returnbool(abs(self))29

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

33 v1 = Vector2d(3, 4)34 print(v1.x, v1.y)35 #3.0 4.0

36 x, y =v137 print(x, y)38 #(3.0, 4.0)

39 print(v1)40 #Vector2d(3.0, 4.0)

41 print("repr(v1),", repr(v1))42 v2 =eval(repr(v1))43 print(v1 ==v2)44 #True

45 print(v1)46 #(3.0, 4.0)

47 octets =bytes(v1)48 print(octets)49 #b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'

50 print(abs(v1))51 #5.0

52 print(bool(v1), bool(Vector2d(0, 0)))53 #(True, False)

备选构造方法

我们可以Vector2d实例转换成字节序列了,那么也应该提供一个方法转换回来。array.array中有个frombytes方法

1 classVector2d:2 """

3 自定义一个二维向量类4 """

5 typecode = 'd'

6 def __init__(self, x, y):7 self.x =x8 self.y =y9

10 def __iter__(self):11 return (i for i in(self.x, self.y))12

13 def __repr__(self):14 return '{}({!r}, {!r})'.format(type(self).__name__, self.x, self.y)15

16 def __str__(self):17 return str(tuple(self)) #已经实现了__iter__方法,self实例是可迭代对象

18

19 def __eq__(self, other):20 return tuple(self) ==tuple(other)21

22 def __abs__(self):23 returnmath.hypot(self.x, self.y)24

25 def __bool__(self):26 returnbool(abs(self))27

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

31 @classmethod32 deffrombytes(cls, octets):33 typecode =chr(octets[0])34 memv = memoryview(octets[1:]).cast(typecode)35 return cls(*memv)36

37 v1 = Vector2d(3, 4)38 print(v1.x, v1.y)39 #3.0 4.0

40 x, y =v141 print(x, y)42 #(3.0, 4.0)

43 print(v1)44 #Vector2d(3.0, 4.0)

45 print("repr(v1),", repr(v1))46 v2 =eval(repr(v1))47 print(v1 ==v2)48 #True

49 print(v1)50 #(3.0, 4.0)

51 octets =bytes(v1)52 print(octets)53 #b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'

54 print(abs(v1))55 #5.0

56 print(bool(v1), bool(Vector2d(0, 0)))57 #(True, False)

58 v2 =Vector2d.frombytes(octets)59 print(v2)

classmethod和staticmethod

classmethod定义了操作类的方法而不是实例。classmethod改变了调用方法的方式,第一个参数是类本身,而不是实例。classmethod最常见的用途就是定义备选函数构造方法,如上面的frombytes,按照约定,类方法的第一个参数名为cls。(实际上,怎么命名都可以)

staticmethod也会改变方法的调用方式,但是第一个蚕食不是特殊的值,事实上,静态方法就是普通的函数,只是碰巧在类的定义体中。

格式化显示

1 classVector2d:2 typecode = 'd'

3 def __init__(self, x, y):4 self.x, self.y =x, y5 def __iter__(self):6 return (i for i in(self.x, self.y))7 def __repr__(self):8 return '{}({!r}, {!r})' %(type(self).__name__, self.x, self.y)9 def __str__(self):10 returnstr(tuple(self))11 def __bytes__(self):12 return (bytes([ord(self.typecode)]) +

13 bytes(array(self.typecode, self)))14 def __eq__(self, other):15 return tuple(self)==tuple(other)16 def __abs__(self):17 returnmath.hypot(self.x, self.y)18 def __bool__(self):19 returnbool(abs(self))20 @classmethod21 deffrombytes(cls, octets):22 typecode =chr(octets[0])23 memv = memoryview(octets[1:]).cast(typecode)24 return cls(*memv)25 def __format__(self, fmt=""):26 if fmt.endswith('p'):27 polar =(abs(self), self.angle())28 s =polar29 outer_fmt = '<{}, {}>'

30 else:31 s =self32 outer_fmt = '({}, {})'

33 components = (format(c, fmt.rstrip('p')) for c ins)34 return outer_fmt.format(*components)35 defangle(self):36 returnmath.atan2(self.y, self.x)37 v1 = Vector2d(3, 4)38 print(format(v1, '.2f'))39 print(format(v1, '.4e'))40 print(format(v1, '.3ep'))

使用__slots__类属性节省空间

python在各个实例中的__dict__字典里存储实例属性,通过之前的学习,我们知道dict字典这种结构是典型的空间换时间,会消耗掉大量的内存,如果要处理数百万的实例,通过__slots__属性,就能节省大量内存,方法是让解释器在类似元组的结构中存储实例属性,而不是字典。(超类的__slots__属性,对子类没有效果)

1 classVector2d:2 __slots__ = ('_x', '_y')3 ...

ps:如果要处理数百万个数值对象,应该使用numpy。

__slots__设计之初是为了节省内存,但是也带来了一个副作用,那就是不能再为实例添加__slots__之外的属性。

需要明确的是:使用__slots__的充分理由应该是为了节省内存,而不是限制实例属性,__slots__是用于优化的,而非约束程序员。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值