Python168的学习笔记6

如何派生内置不可变类型并修改实例化行为。

个人理解,如何派生出自己想要的类。

 1 class IntTuple(tuple):
 2     
 3     def __new__(cls,iterable):
 4         g = (x for x in iterable if isinstance(x, int) and x>0)
 5         return super(IntTuple,cls).__new__(cls,g)
 6     
 7     def __init__(self,iterable):
 8         super(IntTuple,self).__init__(iterable)
 9         
10 t = IntTuple([1,-1,'abc',6,[7,'y'],3])
11 print t

类的创建是在__new__中实现的,所以要修改new。

 

关于使用__slots__,在创建class时,定义slots属性,声明实例属性列表,这就等于关闭掉__dict__属性,dict的作用是允许对class进行动态添加属性。使用slots可以节省内存,对封装有好处。

 

关于上下文管理,也就是在class中设置__enter__,__exit__属性,这样就可以配合with使用了。ps:with语句中,无论如何都会执行exit方法。

在设置__enter__属性时,要注意返回的对象是不是self,一般来说都是。

在设置__exit__属性时,要注意接收的参数, def __exit__(self,exc_type,exc_val,exc_tab),需要接收异常信息。

注意,如果在exit中设置了return Ture。则错误会被包在with中而不传回给最上层。

 

关于property的用法。

 1 class Circle(object):
 2     def __init__(self,r):
 3         self.r = r
 4         
 5     def getR(self):
 6         return round(self.r,2)#四舍五入两位小数
 7     
 8     def setR(self,value):
 9         if not isinstance(value,(int,long,float)):
10             raise ValueError('wrong type.')
11         self.r = float(value)
12     
13     def getArea(self):
14         return round(self.r ** 2* pi)
15     
16     R = property(getR,setR)#将方法定义到属性
17 
18 c =Circle(3.2)
19 print c.R
20 c.R = 5

 

为类添加比较的属性,如__lt__,__le__,__gt__,__ge__,__eq__,__ne__这些属性。(小于,小于等于,大于,大于等于,等于,不等于)

比较两个类的大小,如 r1<r2 实际上就是 r1.__lt__(r2)方法的调用。

但是如果要添加6个属性显得很麻烦,所以可以使用functools.total_ordering方法,将其作为装饰器,赋给class,然后只用定义__lt__,__eq__就可以实现6个属性的比较了。

 1 from functools import total_ordering
 2 from abc import abstractmethod,ABCMeta
 3 
 4 @total_ordering
 5 class Shape(object):
 6     __metaclass__ = ABCMeta#定义这个类为抽象类,不可以被实例化
 7     @abstractmethod#声明定义抽象方法,让各个子类去完善
 8     def area(self):
 9         pass
10     
11     def __lt__(self,obj):
12         if not isinstance(obj,Shape):
13             raise TypeError('obj is not shape.')
14         return self.area() <obj.area()
15     
16     def __eq__(self,obj):
17         if not isinstance(obj,Shape):
18             raise TypeError('obj is not shape.')
19         return self.area() == obj.area()
20 
21 
22 class Rectangle(Shape):
23     def __init__(self,w,h):
24         self.w = w
25         self.h = h
26         
27     def area(self):
28         return self.w *self.h
29     
30 
31 class Circle(Shape):
32     def __init__(self,r):
33         self.r = r
34         
35     def area(self):
36         return self.r ** 2 *3.14
37     
38 r1 = Rectangle(3,5)    
39 r2 = Rectangle(5,5)   
40 c1 = Circle(5) 
41 print r1 > r2
42 print c1 > r1

ps:要注意ABCMeta,abstractmethod的作用,理解抽象类以及抽象方法的定义。

 

深入了解类的构成,如 __get__,__set__,__del__ 这些方法的作用。

 1 #coding:utf8
 2 class Attr(object):
 3     def __init__(self,name,type_):
 4         self.name = name
 5         self.type_ = type_
 6         
 7     def __get__(self,instance,cls):
 8         return instance.__dict__[self.name]
 9     
10     def __set__(self,instance,value):
11         if not isinstance(value,self.type_):
12             raise TypeError('expected an %s' % self.type_)
13         instance.__dict__[self.name] = value
14         
15     def __delete__(self,instance):
16         del instance.__dict__[self.name]
17 
18 class Person(object):
19     name =  Attr('name',str)
20     age = Attr('age',int)
21     height = Attr('height',float)
22     
23 p = Person()
24 
25 p.age = '17' 
26 print p.age#这里就会报错

引入弱引用weakref的概念,弱引用可以创建一种能访问对象,但是不增加访问计数的对象。

ps:当对象被引用时,对象的引用计数+1,而当对象的引用计数为0时,对象将被回收。弱引用的好处是,在某种循环引用里,解决回收不及时的问题。

 1 #coding:utf8
 2 import weakref
 3 
 4 class Data(object):
 5     def __init__(self,value,owner):
 6         self.owner = weakref.ref(owner)#如果不是弱引用,则删除实例也不会回收
 7         self.value = value
 8         
 9     def __del__(self):#回收函数
10         print 'in Data.__del__'
11       
12 class Node(object):
13     def __init__(self,value):
14         self.data = Data(value,self)
15     
16     def __del__(self):
17         print 'in Node.__del__'
18         
19 node = Node(100)
20 del node

ps:注意,需要引用 弱引用的对象时,要用其方法,如:self.owner = weakref.ref(owner),调用self.owner时应为self.owner()

 

通过实例化 方法的名字 来调用

 1 class s1(object):
 2     def A(self):
 3         return 'A'
 4 
 5 class s2(object):
 6     def B(self):
 7         return 'B'
 8 
 9 class s3(object):
10     def C(self):
11         return 'C'
12     
13 def getS(s):
14     for name in ('A','B','C'):
15         f = getattr(s, name,None)#在这里寻找对应的方法,如果找不到就返回none
16         if f:
17             return f()
18         
19 a = s1()
20 b = s2()
21 c = s3()
22 t = [a,b,c]
23 print map(getS,t)

用operator.methodcaller也有类似功能。但是不太明白为什么要用这个。

posted @ 2016-11-12 21:06  Nanrou  阅读(255)  评论(0编辑  收藏  举报