参考:cnblogs.com/linhaifeng/articles/6204014.html
一.isinstance与issubclass
1.isinstance(obj,cls):判断对象obj是否为类cls的实例
class Foo(object):
pass
f1=Foo()
print(isinstance(f1,Foo)) #True
子类的实例也是父类的实例:
class foo:
pass
class bar(foo):
pass
b1=bar()
print(isinstance(b1,bar)) #True
print(isinstance(b1,foo)) #True
2.issubclass(sub,super):判断类sub是否是类super的子类
class Foo():
pass
class Bar(Foo):
pass
print(issubclass(Bar,Foo)) #True
二.__ setattr__,__delattr __, __getattr __
__getattr __(self,item):在调用对象不存在的属性时运行
__ delattr __(self,item):在删除对象的属性时运行
__setattr __(self,key,value):在设置对象的属性时运行
class foo:
def __init__(self,y):
self.y=y
def __getattr__(self,item):
print('执行__getattr__')
def __delattr__(self,item):
print('执行__delattr__')
#def self.item #触发无限递归
self.__dict__.pop(item)
def __setattr__(self,key,value):
print('执行__setattr__')
#self.key=value #初始化结果:maximum recursion depth exceed
#初始化时需设置属性,__setattr__被触发,self.key=value时也是设置属性,再次被触发,发生递归
self.__dict__[key]=value
f1=foo(10)
'''
print(getattr(f1,'y')) #10 #相当于print(f1.y)
f1.sssssss #执行__getattr__
'''
'''
del f1.y #执行__delattr__
'''
'''
#初始化结果:执行__setattr__
print(f1.__dict__) #{'y':10}
'''
三.二次加工标准类型(包装)
1.包装:很多情况下需要基于标准数据类型来定制自己的数据类型,新增/改写方法,这用到了继承/派生
class List(list):
def append(self,p_object):
if type(p_object) is str:
super().append(self,p_object) #相当于list.append(self,p_object)
else:
print('只能添加str')
def show_middle(self):
mid_index=int(len(self)/2)
return self[mid_index]
2.授权:更(geng1)新的方法都是由新类的某部分来处理,已存在的功能就授权给对象的默认属性—可理解为一种包装,不过是通过覆盖__getattr__实现(类似组合)而非通过继承/派生
import time
class Open:
def __init__(self,filename,mode='r',encoding='utf-8'):
self.file=open(filename,mode,encoding=encoding)
self.mode=mode
self.encode=encoding
def write(self,content):
t=time.strftime('%Y-%m-%d %X')
self.file.write('%s%s'%(t,content))
def __getattr__(self,item):
return getattr(self.file,item)
f1=Open('a.txt','r+')
print(f1.read) #获得read方法的内存地址 #read方法被封装进file,触发__getattr__
f1.write('系统崩溃') #成功写入
四.__getattribute __(self,item)
1.在调用对象属性时被触发(不论该属性存在与否)
class foo:
def __init__(self,x):
self.x=x
def __getattribute__(self,item):
print('执行__getattribute__')
f1=foo(1)
f1.x #执行__getattr__
f1.xx #执行__getattr__
2.默认情况下,使用raise AttributeError(‘x’)调用__getattr__
#以下非默认情况下代码!!
class foo:
def __init__(self,x):
self.x=x
def __getattr__(self,x):
print('执行__getattr__')
def __getattribute__(self,item):
if
print('执行__getattribute__')
raise AttributeError('抛出异常')
#模拟抛出异常,打印'AttributeError:抛出异常'
f1=foo(1)
f1.xx #执行__getattribute__ 执行__getattr__
f1.x #执行__getattribute__ 执行__getattr__
五.描述符(见描述符部分)
六.item系列:效果与__ **attr__相同,但使用的是字典形式
1.__getitem __(self,item):以字典形式查询item是否是对象self的属性时被触发
2.__setitem __(self,key,value):以字典形式给对象self添加key=value的属性时被触发
3.__delitem __(self,key):以字典形式删除对象self中的key属性时被触发
class foo:
def __getitem__(self,item):
return self.__dict__[item]
def __setitem__(self,key,value):
self.__dict__[key]=value
def _delitem__(self,key):
self.__dict__.pop(key)
f1=foo()
f1['name']='ale'
print(f1['name']) #ale
def f1['name']
七.__ str __, __repr __, __format __
1.改变对象的字符串显示:__str __ , __repr __(返回值必须为str)
class foo:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self): #print函数/str函数触发obj.__str__()
return '名字是%s,年龄是%s'%(self.name,self.age) #必须return值
f1=foo('alex',18)
print(f1) #名字是alex,年龄是18
#默认为<__main__.foo object at 0x000000000B5AF98>
class foo:
def __init__(self,name,age):
self.name=name
self.age=age
def __repr__(self): #交互式解释器/repr函数触发obj.__repr__()
return '名字是%s,年龄是%s'%(self.name,self.age)
f1=foo('alex','18')
f1 #名字是alex,年龄是18
print(f1) #名字是alex,年龄是18
#如果__str__没有被定义,会使用__repr__来代替输出
6种基本数据类型都有__ str__方法
注意,必须是交互式才会触发__repr __
2.自定制格式化字符串:a.__ format__(self,format_spec=’’)
format_spec用于自定义格式;默认为空字符串,此时为替换占位符
class date:
def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=day
d1=date(2020,02,05)
x='{0.year}{0.month}{0.day}'.format(d1) #调用d1.__format__()方法
print(x) #20200205 #可扩展性差
format_dict={'ymd':'{0.year}{0.month}{0.day}','y:m:d':'{0.year}:{0.month}:{0.day}','m-d-y':'{0.month}-{0.day}-{0.year}'}
class date:
def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=day
def __format__(self,format_spec):
if not format_spec:
fm='ymd'
elif format_spec not in format_dict:
return '要求格式不存在'
else:
fm=format_dict[format_spec]
return fm.format(self) #必须返回str
d1=date('2020','02','05')
print(format(d1,'ymd'))
八.__ slots __—内存优化工具,也可防止用户给实例添加属性
1.一个类变量,变量值可以是list/tuple/iterator/str
定义__slots__后,其会为实例使用一种更紧凑的内部表示,实例通过一个很小的固定大小的数组来构建,而非为每个实例定义字典,__slots__中列出的属性在内部被映射到该数组的指定小标上
2.优点:字典会占用大量内存,如果有一个属性很少/实例很多的类,使用__slots__可节省内存
缺点:不能给实例添加新属性,只能使用__slots__中定义的属性
3.注意:__slots__很多特性依赖于普通的基于字典的实现;定义了__slots__的类不再支持一些普通类的特性(如多继承)—>只在经常使用的用作数据结构的类上使用
class Foo:
#__slots__=['name','age'] #类似于属性字典{'name'=None,'age'=None}
__slots__='name'
f1=Foo() #实例不再具有__slots__属性/属性字典
f1.name='Ale'
print(f1.__slots__) #找到类的__slots__属性
print(f1.name) #Ale
九.__ next__和__ iter__实现迭代器协议
class foo:
def __init__(self,n):
self.n=n
def __iter__(self):
return self
def __next__(self):
if self.n>100:
raise StopIteration('终止') #抛出异常,打印StopIteration:终止
self.n+=1
return self.n
f1=foo(1)
print(f1.__next__()) #2
print(next(f1)) #3
for i in f1:
print(i) #成功循环
class fib_seq:
def __init__(self):
self.a=1
self.b=1
def __iter__(self):
return self
def __next__(self):
self.a=self.b
self.b=self.a+self.b
return self.a
f1=fib_seq()
for i in f1:
print(i)
十.__ doc__
1.返回文档注释
class foo:
'我是描述信息'
pass
print(foo.__doc__) #我是描述信息
2.该属性无法被继承:每个类中如未定义自动加入’__ doc__=None’,且无法删除
class foo:
'我是描述信息'
pass
class bar(foo):
pass
print(bar.__doc__) #None
十一.__ module__和__class __
1.__ module__:返回当前操作的对象所在的模块
2.__ class__:返回当前操作的对象的类
十二.析构方法__del __
1.当对象在内存中被释放时自动触发执行
2.一般无需定义(python为高级语言,内存分配/释放交给解释器执行,该方法是由解释器在垃圾回收时自动触发执行)
class foo:
def __init__(self,name):
self.name=name
def __del__(self):
print('我执行啦')
f1=foo('alex')
'''
del f1.name
print('---')
#--- '我执行啦' #文件执行完毕释放内存
'''
'''
def f1
print('---')
#'我执行啦' --- #回收实例占用的内存
'''
- 执行完毕为什么没有再回收一次
十三.__ enter__和__exit __
1.__enter __(self):执行with语句(实例化)时触发
返回值赋值给as后的变量名
2.__ exit__(self, exc_type, exc_val, exc_tb):with语句中代码全部执行完毕后/发生异常时触发—__exit __执行完毕代表with语句执行完毕
参数说明:三个参数分别为异常类型/异常值/追溯信息,无异常时均为None
注意:with语句中代码块出现异常,则with后的代码都无法执行
如果__exit__()返回True,那么异常会被清空,with后语句正常执行(但with语句内之后的代码不再执行)
用途:把代码块放入with中执行,with结束后,自动完成清理;在需要管理一些资源如文件,网络连接和锁的编程环境中,可在__exit__中定制自动释放资源的机制
3.上下文管理协议
with open('a.txt') as f:
pass
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
with Open('a.txt') as f: #__enter__返回值赋值给f
print('=====>执行代码块')
# print(f,f.name)
4.模拟Open:
class Open:
def __init__(self,filepath,mode='r',encoding='utf-8'):
self.filepath=filepath
self.mode=mode
self.encoding=encoding
def __enter__(self):
# print('enter')
self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
# print('exit')
self.f.close()
return True
def __getattr__(self, item):
return getattr(self.f,item)
with Open('a.txt','w') as f:
print(f)
f.write('aaaaaa')
f.wasdf #抛出异常,交给__exit__处理
十四.__ call__
对象名()/类名()()触发执行(需自行定义,否则不存在导致报错)
class foo:
def __call__(self,*args,**kwargs):
print('执行')
f1=foo()
f1() #执行
十五.元类metaclass:见元类部分
十六.重载
1.一些特殊方法:
2.每个运算符都对应了相应的方法:
2.重写上面的特殊方法,即实现了’运算符的重载’
class Person:
def __init__(self,name,age):
self.name=name
self._age=age
def __str__(self):
#将对象转换成str,一般用于print方法
return '名字是{0},年龄是{1}'.format(self.name,self._age)
def __add__(self,other):
if isinstance(other,Person):
return self.name+other.name
else:
return '不是同类对象,不能相加'
p=Person('A',18)
q=Person('B',19)
print(p)
x=p+q
print(q)
#结果:
#名字是A,年龄是18
#A-B