初学者python笔记(类的装饰器、property方法、元类)

147 阅读5分钟

文章目录


本篇是面向对象编程的进阶知识,内容稍微有点抽象,但是每处都标足了注释和运行结果,可以参考着学习。内容主要涉及上下文协议管理、类的装饰器使用、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

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

运行结果:
setter和deleter

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的属性字典

运行结果:
自定义元类