一、知识储备
1、1--isinstance(obj,cls)检查是否obj是否是类 cls 的对象
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo(object): 2 pass 3 4 obj = Foo() 5 6 isinstance(obj, Foo) isinstance(1,int) 返回一个布尔值 True
1、2--issubclass(sub, super)检查sub类是否是 super 类的派生类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo(object): 2 pass 3 4 class Bar(Foo): 5 pass 6 7 issubclass(Bar, Foo)
二 反射
2、1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
四个可以实现自省的函数(用字符串去操作类或对象的属性)
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
1、hasattr(object,name)判断object中有没有一个name字符串对应的方法或属性返回一个布尔值
2、getattr(object,name,default = None)如果没有这个name会报错None 这边可以自己定义为‘XXXXXXXXXXXXX’内容 类似于raise TypeError ‘XXXX’
3、setattr(object,name,name_value) 添加修改属性
4、delattr(object,name) 删除
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class BlackMedium: 2 feature='Ugly' 3 def __init__(self,name,addr): 4 self.name=name 5 self.addr=addr 6 7 def sell_house(self): 8 print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name) 9 def rent_house(self): 10 print('%s 黑中介租房子啦,傻逼才租呢' %self.name) 11 12 b1=BlackMedium('万成置地','回龙观天露园') 13 14 #检测是否含有某属性 15 print(hasattr(b1,'name')) 16 print(hasattr(b1,'sell_house')) 17 18 #获取属性 19 n=getattr(b1,'name') 20 print(n) 21 func=getattr(b1,'rent_house') 22 func() 23 24 # getattr(b1,'aaaaaaaa') #报错 25 print(getattr(b1,'aaaaaaaa','不存在啊')) 26 27 #设置属性 28 setattr(b1,'sb',True) 29 setattr(b1,'show_name',lambda self:self.name+'sb') 30 print(b1.__dict__) 31 print(b1.show_name(b1)) 32 33 #删除属性 34 delattr(b1,'addr') 35 delattr(b1,'show_name') 36 delattr(b1,'show_name111')#不存在,则报错 37 38 print(b1.__dict__) 39 40 四个方法的使用演示
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo(object): 2 3 staticField = "old boy" 4 5 def __init__(self): 6 self.name = 'wupeiqi' 7 8 def func(self): 9 return 'func' 10 11 @staticmethod 12 def bar(): 13 return 'bar' 14 15 print getattr(Foo, 'staticField') 16 print getattr(Foo, 'func') 17 print getattr(Foo, 'bar') 18 19 类也是对象
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import sys 5 def s1(): 6 print 's1' 7 8 9 def s2(): 10 print 's2' 11 12 13 this_module = sys.modules[__name__] 14 hasattr(this_module, 's1') 15 getattr(this_module, 's2') 16 17 反射当前模块成员
2、2 用反射的好处
好处一:实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class FtpClient: 2 'ftp客户端,但是还么有实现具体的功能' 3 def __init__(self,addr): 4 print('正在连接服务器[%s]' %addr) 5 self.addr=addr
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #from module import FtpClient 2 f1=FtpClient('192.168.1.1') 3 if hasattr(f1,'get'): 4 func_get=getattr(f1,'get') 5 func_get() 6 else: 7 print('---->不存在此方法') 8 print('处理其他的逻辑')
2、3__setattr__,__delattr__,__getattr__
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo: 2 x=1 3 def __init__(self,y): 4 self.y=y 5 6 def __getattr__(self, item): 7 print('----> from getattr:你找的属性不存在') 8 9 10 def __setattr__(self, key, value): 11 print('----> from setattr') 12 # self.key=value #这就无限递归了,你好好想想 13 # self.__dict__[key]=value #应该使用它 14 15 def __delattr__(self, item): 16 print('----> from delattr') 17 # del self.item #无限递归了 18 self.__dict__.pop(item) 19 20 #__setattr__添加/修改属性会触发它的执行 21 f1=Foo(10) 22 print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 23 f1.z=3 24 print(f1.__dict__) 25 26 #__delattr__删除属性的时候会触发 27 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作 28 del f1.a 29 print(f1.__dict__) 30 31 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发 32 f1.xxxxxx 33 34 三者的用法演示
2、4二次加工标准类型(包装)
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid 2 def append(self, p_object): 3 ' 派生自己的append:加上类型检查' 4 if not isinstance(p_object,int): 5 raise TypeError('must be int') 6 super().append(p_object) 7 8 @property 9 def mid(self): 10 '新增自己的属性' 11 index=len(self)//2 12 return self[index] 13 14 l=List([1,2,3,4]) 15 print(l) 16 l.append(5) 17 print(l) 18 # l.append('1111111') #报错,必须为int类型 19 20 print(l.mid) 21 22 #其余的方法都继承list的 23 l.insert(0,-123) 24 print(l) 25 l.clear() 26 print(l) 27 28 二次加工标准类型(基于继承实现)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class List(list): 2 def __init__(self,item,tag=False): 3 super().__init__(item) 4 self.tag=tag 5 def append(self, p_object): 6 if not isinstance(p_object,str): 7 raise TypeError 8 super().append(p_object) 9 def clear(self): 10 if not self.tag: 11 raise PermissionError 12 super().clear() 13 14 l=List([1,2,3],False) 15 print(l) 16 print(l.tag) 17 18 l.append('saf') 19 print(l) 20 21 # l.clear() #异常 22 23 l.tag=True 24 l.clear() 25 26 练习(clear加权限限制)
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。实现授权的关键点就是覆盖__getattr__方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 import time 2 class FileHandle: 3 def __init__(self,filename,mode='r',encoding='utf-8'): 4 self.file=open(filename,mode,encoding=encoding) 5 def write(self,line): 6 t=time.strftime('%Y-%m-%d %T') 7 self.file.write('%s %s' %(t,line)) 8 9 def __getattr__(self, item): 10 return getattr(self.file,item) 11 12 f1=FileHandle('b.txt','w+') 13 f1.write('你好啊') 14 f1.seek(0) 15 print(f1.read()) 16 f1.close() 17 18 授权示范一
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #_*_coding:utf-8_*_ 2 __author__ = 'Linhaifeng' 3 #我们来加上b模式支持 4 import time 5 class FileHandle: 6 def __init__(self,filename,mode='r',encoding='utf-8'): 7 if 'b' in mode: 8 self.file=open(filename,mode) 9 else: 10 self.file=open(filename,mode,encoding=encoding) 11 self.filename=filename 12 self.mode=mode 13 self.encoding=encoding 14 15 def write(self,line): 16 if 'b' in self.mode: 17 if not isinstance(line,bytes): 18 raise TypeError('must be bytes') 19 self.file.write(line) 20 21 def __getattr__(self, item): 22 return getattr(self.file,item) 23 24 def __str__(self): 25 if 'b' in self.mode: 26 res="<_io.BufferedReader name='%s'>" %self.filename 27 else: 28 res="<_io.TextIOWrapper name='%s' mode='%s' encoding='%s'>" %(self.filename,self.mode,self.encoding) 29 return res 30 f1=FileHandle('b.txt','wb') 31 # f1.write('你好啊啊啊啊啊') #自定制的write,不用在进行encode转成二进制去写了,简单,大气 32 f1.write('你好啊'.encode('utf-8')) 33 print(f1) 34 f1.close() 35 36 授权示范二
2、5__getattribute__
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo: 2 def __init__(self,x): 3 self.x=x 4 5 def __getattr__(self, item): 6 print('执行的是我') 7 # return self.__dict__[item] 8 9 f1=Foo(10) 10 print(f1.x) 11 f1.xxxxxx #不存在的属性访问,触发__getattr__
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo: 2 def __init__(self,x): 3 self.x=x 4 5 def __getattribute__(self, item): 6 print('不管是否存在,我都会执行') 7 8 f1=Foo(10) 9 f1.x 10 f1.xxxxxx
2、6描述符(__get__,__set__,__delete__)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议 2 __get__():调用一个属性时,触发 3 __set__():为一个属性赋值时,触发 4 __delete__():采用del删除属性时,触发 5 class Foo: #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符 6 def __get__(self, instance, owner): 7 pass 8 def __set__(self, instance, value): 9 pass 10 def __delete__(self, instance): 11 pass
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中) 2 3 class Foo: 4 def __get__(self, instance, owner): 5 print('触发get') 6 def __set__(self, instance, value): 7 print('触发set') 8 def __delete__(self, instance): 9 print('触发delete') 10 11 #包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法 12 f1=Foo() 13 f1.name='egon' 14 f1.name 15 del f1.name 16 #疑问:何时,何地,会触发这三个方法的执行 17 18 引子:描述符类产生的实例进行属性操作并不会触发三个方法的执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #描述符Str 2 class Str: 3 def __get__(self, instance, owner): 4 print('Str调用') 5 def __set__(self, instance, value): 6 print('Str设置...') 7 def __delete__(self, instance): 8 print('Str删除...') 9 10 #描述符Int 11 class Int: 12 def __get__(self, instance, owner): 13 print('Int调用') 14 def __set__(self, instance, value): 15 print('Int设置...') 16 def __delete__(self, instance): 17 print('Int删除...') 18 19 class People: 20 name=Str() 21 age=Int() 22 def __init__(self,name,age): #name被Str类代理,age被Int类代理, 23 self.name=name 24 self.age=age 25 26 #何地?:定义成另外一个类的类属性 27 28 #何时?:且看下列演示 29 30 p1=People('alex',18) 31 32 #描述符Str的使用 33 p1.name 34 p1.name='egon' 35 del p1.name 36 37 #描述符Int的使用 38 p1.age 39 p1.age=18 40 del p1.age 41 42 #我们来瞅瞅到底发生了什么 43 print(p1.__dict__) 44 print(People.__dict__) 45 46 #补充 47 print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的 48 print(type(p1).__dict__ == People.__dict__)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 3 描述符分两种 2 一 数据描述符:至少实现了__get__()和__set__() 3 4 1 class Foo: 5 2 def __set__(self, instance, value): 6 3 print('set') 7 4 def __get__(self, instance, owner): 8 5 print('get') 9 10 二 非数据描述符:没有实现__set__() 11 12 1 class Foo: 13 2 def __get__(self, instance, owner): 14 3 print('get')
4 注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #描述符Str 2 class Str: 3 def __get__(self, instance, owner): 4 print('Str调用') 5 def __set__(self, instance, value): 6 print('Str设置...') 7 def __delete__(self, instance): 8 print('Str删除...') 9 10 class People: 11 name=Str() 12 def __init__(self,name,age): #name被Str类代理,age被Int类代理, 13 self.name=name 14 self.age=age 15 16 17 #基于上面的演示,我们已经知道,在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是实例的属性字典 18 19 #那既然描述符被定义成了一个类属性,直接通过类名也一定可以调用吧,没错 20 People.name #恩,调用类属性name,本质就是在调用描述符Str,触发了__get__() 21 22 People.name='egon' #那赋值呢,我去,并没有触发__set__() 23 del People.name #赶紧试试del,我去,也没有触发__delete__() 24 #结论:描述符对类没有作用-------->傻逼到家的结论 25 26 ''' 27 原因:描述符在使用时被定义成另外一个类的类属性,因而类属性比二次加工的描述符伪装而来的类属性有更高的优先级 28 People.name #恩,调用类属性name,找不到就去找描述符伪装的类属性name,触发了__get__() 29 30 People.name='egon' #那赋值呢,直接赋值了一个类属性,它拥有更高的优先级,相当于覆盖了描述符,肯定不会触发描述符的__set__() 31 del People.name #同上 32 '''
2.数据描述符
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #描述符Str 2 class Str: 3 def __get__(self, instance, owner): 4 print('Str调用') 5 def __set__(self, instance, value): 6 print('Str设置...') 7 def __delete__(self, instance): 8 print('Str删除...') 9 10 class People: 11 name=Str() 12 def __init__(self,name,age): #name被Str类代理,age被Int类代理, 13 self.name=name 14 self.age=age 15 16 17 p1=People('egon',18) 18 19 #如果描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操作,于p1本身无关了,相当于覆盖了实例的属性 20 p1.name='egonnnnnn' 21 p1.name 22 print(p1.__dict__)#实例的属性字典中没有name,因为name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了 23 del p1.name
3.实例属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo: 2 def func(self): 3 print('我胡汉三又回来了') 4 f1=Foo() 5 f1.func() #调用类的方法,也可以说是调用非数据描述符 6 #函数是一个非数据描述符对象(一切皆对象么) 7 print(dir(Foo.func)) 8 print(hasattr(Foo.func,'__set__')) 9 print(hasattr(Foo.func,'__get__')) 10 print(hasattr(Foo.func,'__delete__')) 11 #有人可能会问,描述符不都是类么,函数怎么算也应该是一个对象啊,怎么就是描述符了 12 #笨蛋哥,描述符是类没问题,描述符在应用的时候不都是实例化成一个类属性么 13 #函数就是一个由非描述符类实例化得到的对象 14 #没错,字符串也一样 15 16 17 f1.func='这是实例属性啊' 18 print(f1.func) 19 20 del f1.func #删掉了非数据 21 f1.func()
4.非数据描述符
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo: 2 def __set__(self, instance, value): 3 print('set') 4 def __get__(self, instance, owner): 5 print('get') 6 class Room: 7 name=Foo() 8 def __init__(self,name,width,length): 9 self.name=name 10 self.width=width 11 self.length=length 12 13 14 #name是一个数据描述符,因为name=Foo()而Foo实现了get和set方法,因而比实例属性有更高的优先级 15 #对实例的属性操作,触发的都是描述符的 16 r1=Room('厕所',1,1) 17 r1.name 18 r1.name='厨房' 19 20 21 22 class Foo: 23 def __get__(self, instance, owner): 24 print('get') 25 class Room: 26 name=Foo() 27 def __init__(self,name,width,length): 28 self.name=name 29 self.width=width 30 self.length=length 31 32 33 #name是一个非数据描述符,因为name=Foo()而Foo没有实现set方法,因而比实例属性有更低的优先级 34 #对实例的属性操作,触发的都是实例自己的 35 r1=Room('厕所',1,1) 36 r1.name 37 r1.name='厨房'
5.找不到的属性触发__getattr__()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo: 2 def func(self): 3 print('我胡汉三又回来了') 4 5 def __getattr__(self, item): 6 print('找不到了当然是来找我啦',item) 7 f1=Foo() 8 9 f1.xxxxxxxxxxx
5 描述符使用
众所周知,python是弱类型语言,即参数的赋值没有类型限制,下面我们通过描述符机制来实现类型限制功能
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Str: 2 def __init__(self,name): 3 self.name=name 4 def __get__(self, instance, owner): 5 print('get--->',instance,owner) 6 return instance.__dict__[self.name] 7 8 def __set__(self, instance, value): 9 print('set--->',instance,value) 10 instance.__dict__[self.name]=value 11 def __delete__(self, instance): 12 print('delete--->',instance) 13 instance.__dict__.pop(self.name) 14 15 16 class People: 17 name=Str('name') 18 def __init__(self,name,age,salary): 19 self.name=name 20 self.age=age 21 self.salary=salary 22 23 p1=People('egon',18,3231.3) 24 25 #调用 26 print(p1.__dict__) 27 p1.name 28 29 #赋值 30 print(p1.__dict__) 31 p1.name='egonlin' 32 print(p1.__dict__) 33 34 #删除 35 print(p1.__dict__) 36 del p1.name 37 print(p1.__dict__)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Str: 2 def __init__(self,name): 3 self.name=name 4 def __get__(self, instance, owner): 5 print('get--->',instance,owner) 6 return instance.__dict__[self.name] 7 8 def __set__(self, instance, value): 9 print('set--->',instance,value) 10 instance.__dict__[self.name]=value 11 def __delete__(self, instance): 12 print('delete--->',instance) 13 instance.__dict__.pop(self.name) 14 15 16 class People: 17 name=Str('name') 18 def __init__(self,name,age,salary): 19 self.name=name 20 self.age=age 21 self.salary=salary 22 23 #疑问:如果我用类名去操作属性呢 24 People.name #报错,错误的根源在于类去操作属性时,会把None传给instance 25 26 #修订__get__方法 27 class Str: 28 def __init__(self,name): 29 self.name=name 30 def __get__(self, instance, owner): 31 print('get--->',instance,owner) 32 if instance is None: 33 return self 34 return instance.__dict__[self.name] 35 36 def __set__(self, instance, value): 37 print('set--->',instance,value) 38 instance.__dict__[self.name]=value 39 def __delete__(self, instance): 40 print('delete--->',instance) 41 instance.__dict__.pop(self.name) 42 43 44 class People: 45 name=Str('name') 46 def __init__(self,name,age,salary): 47 self.name=name 48 self.age=age 49 self.salary=salary 50 print(People.name) #完美,解决
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Str: 2 def __init__(self,name,expected_type): 3 self.name=name 4 self.expected_type=expected_type 5 def __get__(self, instance, owner): 6 print('get--->',instance,owner) 7 if instance is None: 8 return self 9 return instance.__dict__[self.name] 10 11 def __set__(self, instance, value): 12 print('set--->',instance,value) 13 if not isinstance(value,self.expected_type): #如果不是期望的类型,则抛出异常 14 raise TypeError('Expected %s' %str(self.expected_type)) 15 instance.__dict__[self.name]=value 16 def __delete__(self, instance): 17 print('delete--->',instance) 18 instance.__dict__.pop(self.name) 19 20 21 class People: 22 name=Str('name',str) #新增类型限制str 23 def __init__(self,name,age,salary): 24 self.name=name 25 self.age=age 26 self.salary=salary 27 28 p1=People(123,18,3333.3)#传入的name因不是字符串类型而抛出异常
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Typed: 2 def __init__(self,name,expected_type): 3 self.name=name 4 self.expected_type=expected_type 5 def __get__(self, instance, owner): 6 print('get--->',instance,owner) 7 if instance is None: 8 return self 9 return instance.__dict__[self.name] 10 11 def __set__(self, instance, value): 12 print('set--->',instance,value) 13 if not isinstance(value,self.expected_type): 14 raise TypeError('Expected %s' %str(self.expected_type)) 15 instance.__dict__[self.name]=value 16 def __delete__(self, instance): 17 print('delete--->',instance) 18 instance.__dict__.pop(self.name) 19 20 21 class People: 22 name=Typed('name',str) 23 age=Typed('name',int) 24 salary=Typed('name',float) 25 def __init__(self,name,age,salary): 26 self.name=name 27 self.age=age 28 self.salary=salary 29 30 p1=People(123,18,3333.3) 31 p1=People('egon','18',3333.3) 32 p1=People('egon',18,3333)
大刀阔斧之后我们已然能实现功能了,但是问题是,如果我们的类有很多属性,你仍然采用在定义一堆类属性的方式去实现,low,这时候我需要教你一招:独孤九剑
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 def decorate(cls): 2 print('类的装饰器开始运行啦------>') 3 return cls 4 5 @decorate #无参:People=decorate(People) 6 class People: 7 def __init__(self,name,age,salary): 8 self.name=name 9 self.age=age 10 self.salary=salary 11 12 p1=People('egon',18,3333.3)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 def typeassert(**kwargs): 2 def decorate(cls): 3 print('类的装饰器开始运行啦------>',kwargs) 4 return cls 5 return decorate 6 @typeassert(name=str,age=int,salary=float) #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People) 7 class People: 8 def __init__(self,name,age,salary): 9 self.name=name 10 self.age=age 11 self.salary=salary 12 13 p1=People('egon',18,3333.3)
终极大招
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Typed: 2 def __init__(self,name,expected_type): 3 self.name=name 4 self.expected_type=expected_type 5 def __get__(self, instance, owner): 6 print('get--->',instance,owner) 7 if instance is None: 8 return self 9 return instance.__dict__[self.name] 10 11 def __set__(self, instance, value): 12 print('set--->',instance,value) 13 if not isinstance(value,self.expected_type): 14 raise TypeError('Expected %s' %str(self.expected_type)) 15 instance.__dict__[self.name]=value 16 def __delete__(self, instance): 17 print('delete--->',instance) 18 instance.__dict__.pop(self.name) 19 20 def typeassert(**kwargs): 21 def decorate(cls): 22 print('类的装饰器开始运行啦------>',kwargs) 23 for name,expected_type in kwargs.items(): 24 setattr(cls,name,Typed(name,expected_type)) 25 return cls 26 return decorate 27 @typeassert(name=str,age=int,salary=float) #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People) 28 class People: 29 def __init__(self,name,age,salary): 30 self.name=name 31 self.age=age 32 self.salary=salary 33 34 print(People.__dict__) 35 p1=People('egon',18,3333.3)
2、7 str
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #_*_coding:utf-8_*_ 2 __author__ = 'Linhaifeng' 3 format_dict={ 4 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 5 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 6 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 7 } 8 class School: 9 def __init__(self,name,addr,type): 10 self.name=name 11 self.addr=addr 12 self.type=type 13 14 def __repr__(self): 15 return 'School(%s,%s)' %(self.name,self.addr) 16 def __str__(self): 17 return '(%s,%s)' %(self.name,self.addr) 18 19 def __format__(self, format_spec): 20 # if format_spec 21 if not format_spec or format_spec not in format_dict: 22 format_spec='nat' 23 fmt=format_dict[format_spec] 24 return fmt.format(obj=self) 25 26 s1=School('oldboy1','北京','私立') 27 print('from repr: ',repr(s1)) 28 print('from str: ',str(s1)) 29 print(s1) 30 31 ''' 32 str函数或者print函数--->obj.__str__() 33 repr或者交互式解释器--->obj.__repr__() 34 如果__str__没有被定义,那么就会使用__repr__来代替输出 35 注意:这俩方法的返回值必须是字符串,否则抛出异常 36 ''' 37 print(format(s1,'nat')) 38 print(format(s1,'tna')) 39 print(format(s1,'tan')) 40 print(format(s1,'asfdasdffd'))
2、8 __call__
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 class Foo: 2 3 def __init__(self): 4 pass 5 6 def __call__(self, *args, **kwargs): 7 8 print('__call__') 9 10 11 obj = Foo() # 执行 __init__ 12 obj() # 执行 __call__