文章目录
本篇是面向对象编程的进阶知识,内容稍微有点抽象,但是每处都标足了注释和运行结果,可以参考着学习。内容主要涉及上下文协议管理、类的装饰器使用、property方法、元类四个方面
上下文协议管理
就是with … as …这种方式的使用原理
class Foo:
def __init__(self,name,age):
self.name= name
self.age= age
def __enter__(self): #当调用类Foo时就会触发__enter__方法
print('__enter__正在被触发')
return self #将类Foo的属性作为返回值
def __exit__(self,exc_type,exc_val,exc_tb): #self后的三个参数为必要属性
print('执行__exit__')
#当整个类执行完毕以后就会触发exit的运行,
#或者执行过程中出现了异常也会触发exit方法的运行,并停止程序的运行
#但若返回一个True就不会停止整个程序的运行,只是停止类的执行,后续代码可以继续执行
return True
with Foo('a.txt',18) as f: #只要调用了with Foo...就是触发__enter__
#将一个文件传入Foo中,因为返回值是self属性,所以f就代表了self
print(f.name) #可直接调用,相当于self.name
#一个错误语句
print(djksjsgg)
#with ... as ...就是上下文协议管理,打开文件也是这个原理,当文件执行完毕后会自动关闭
with open('a.txt','r',encoding='gbk') as fi:
re = fi.read()
print(re)
print('===============》》》结束')
运行结果:
类的装饰器基本原理
要知道,在Python中,一切皆对象;所以装饰器不仅可以修饰函数,还可以修饰类;可以用函数来定义,也可以用类(描述符)来定义
#定义一个装饰器(本质上就是个修饰函数的函数)
def adorn1(func):
print('=========>>>')
func.x = 1314 #给函数加一属性x
return func
@adorn1 #加上装饰器,相当于test=deco(test),把原函数放进装饰器处理后返回给原函数
def test():
print('test函数运行了')
test() #调用函数
#神奇一幕,一切皆对象,就连函数都可以有属性字典
print(test.x) #输出函数的属性x
print(test.__dict__) #输出函数的属性字典
print('===========================>>>')
#修饰类的装饰器
def adorn2(obj):
print('obj的所属类是:',obj) #传入一个类到obj形参,就可以处理类的属性了
obj.x = 520 #增加属性字典的键值对
return obj #返回被修饰后的类
#在类上用装饰器,同样适用
@adorn2
class Foo:
pass
f1 = Foo() #实例化
#print(f1) #输出类的内存地址信息
print(f1.x)
运行结果:
property方法的巧用
利用描述符自定制property
#@property原理,就是一个装饰器
class Self_property:
def __init__(self,func): #获得属性并但不处理属性
self.func = func
#将Self_property做成一个描述符(一个类修饰另外一个类),以得到返回值
def __get__(self,instance,owner): #后两个的必须参数有
print('get被触发!,instance就是:',instance)
res = self.func(instance) #返回func的运行结果,即area的运行结果
return res
class Room:
def __init__(self,name,width,length):
self.name = name
self.width = width
self.length = length
#@property
#类的装饰器,相当于area=property(area),效果是使area函数能后执行一遍
@Self_property
def area(self):
return self.width * self.length #返回宽*长(面积)
print('==============Room的字典==============')
print(Room.__dict__) #加了描述符后Room的属性里就有了这个描述符
print('\n===============实例化结果==============')
r1 = Room('澡堂',5,5) #实例化
print('面积是:',r1.area)
#有了Self_property后,就与property有了一样的效果,可以直接运行类内部的函数
运行结果:
property下的setter与deleter
class Foo:
@property
def TTT(self):
print('TTT被运行')
@TTT.setter #当设置值的时候会触发TTT.setter下定义的函数
def TTT(self,val):
print('set的时候运行setter',val)
@TTT.deleter #当删除值的时候触发TTT.delete下定义的函数
def TTT(self):
print('del的时候触发deleter')
f = Foo()
f.TTT #运行TTT函数
f.TTT='我被改了' #将TTT属性改为值'我被改了'
del f.TTT
运行结果:
Python的元类
元类的概念
就是类的类,是类的模板,是用来控制如何创建类的;
元类的实例就是类,就像类的实例就是对象
class Foo:
pass
f1 = Foo() #实例化对象f1
#输出类型
#print(type(f1)) #f1的类就是Foo
print(type(Foo)) #Foo的类就是type,就是说所有的类都是属于type类
#给元类加self属性
def __init__(self,name,age):
self.name = name
self.age = age
#加其他函数属性
def test(self):
print('这是test函数属性')
#通过元类来定义对象,因为一切皆对象,所以由type定义来的对象就一个类
Foo2 = type('Foo',(object,),{'name':'View','__init__':__init__,'test':test})
#表明定义一个继承Foo的类,里面有一个键值对'name':'View'
print(Foo2)
print('==========Foo2属性字典==========')
print(Foo2.__dict__)
f2 = Foo2('路飞','19') #用新类实例化对象f2
print(f2.name) #输出f2的数据属性
f2.test() #运行函数属性
运行结果:
自定义元类
class MyType(type): #一个继承type的类
def __init_(self,a,b,c): #元类必须有4个参数
print('我是元类函数!',self.name)
print(a,b,c)
def __call__(self,*args,**kwargs): #定义__call__方法
obj = object.__new__(self) #新建一个对象来把Foo传入的参数变为MyType的属性
self.__init__(obj,*args,**kwargs)
return obj
#MyType来定义类
class Foo(metaclass=MyType): #相当于Mytype('Foo',(object,),{})
def __init__(self,name):
self.name = name #封装从MyType传来的属性
#实例化
f1= Foo('View')
#Foo这个用MyType定义的类不会自动触发__init__方法,只会触发__call__方法
print(Foo.__dict__,'\n') #输出Foo的属性字典,并补包括'name': 'View'
print(f1.__dict__) #输出f1的属性字典
运行结果: