Python教程

python基础14-__enter__/__exit__/描述符管理实例的实参类型控制/类的装饰器/自定制property/自定义元类

本文主要是介绍python基础14-__enter__/__exit__/描述符管理实例的实参类型控制/类的装饰器/自定制property/自定义元类,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
  • 上下文管理协议

  • 操作文件有三步骤
  1. 打开文件,赋值给一个文件句柄
  2. 文件操作
  3. 关闭文件
  • with open('a.txt') as f:#open()也是工厂函数,用这种方式不用关闭函数
  • 应用场景,文件,网络连接,也需要打开关闭操作,和锁的编程环境
  • class Foo:
        def __init__(self, name):
            self.name = name
    
        def __enter__(self):
            print('执行enter')
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('执行exit')
            print(exc_type)#异常类
            print(exc_val)#异常值
            print(exc_tb)#异常的追踪信息
            # return True#把异常吞了
            # 可以在exit方法中添加close()方法
    
    with Foo('a.txt') as f:#这句会触发enter方法,enter方法的return值赋值给f
        # 等同于f=obj.enter()
        print(f)
        #print(sdafasdfh)#一遇到错误就执行exit方法
        print(f.name)
    print('000000')
  • 描述符应用

  • 描述符本身是新式类,被代理的类也应该是新式类
  • 必须把描述符定义成类的类属性,不能定义到构造函数init中
  • Python是弱类型语言,即不用定义变量的类型即可使用,没有类型检测的功能
  • # 实现针对传入值的类型检查
    class Typed:
        def __init__(self, key, expected_type):
            self.key = key
            self.expected_type = expected_type
    
        def __get__(self, instance, owner):  # instance是实例本身,owner是实例的拥有者,即类名
            print('这是get方法')
            # print('instance参数【%s】' % instance)
            # print('owner参数【%s】' % owner)
            return instance.__dict__[self.key]  # 返回实例字典中的值
    
        def __set__(self, instance, value):  # value是key的属性值
            print('set方法')
            # print('instance参数【%s】' % instance)
            # print('value参数【%s】' % value)
            if not isinstance(value, self.expected_type):  # 如果name不是str类型,则不让设置key
                # print('你传入的类型不是字符串,错误')
                # return
                raise TypeError('%s 传入的类型不是%s' % (self.key, self.expected_type))
            instance.__dict__[self.key] = value
    
        def __delete__(self, instance):
            print('delete方法')
            # print('instance参数【%s】' % instance)
            instance.__dict__.pop(self.key)
    
    
    class People:
        name = Typed('name', str)  # 实例的数据属性是字典形式存储的,是字符串格式,将该name数据属性代理给描述符
        age = Typed('age', int)
    
        def __init__(self, name, age, salary):
            self.name = name
            self.age = age
            self.salary = salary
    
    
    # p1 = People('alex', 13, 13.3)
    # print(p1.__dict__)
    # p1 = People(122, 13, 13.3)
    p1 = People('alex', '13', 13.3)
    print(p1.__dict__)
    
    # print(p1.name)
    
    # p1.name
    # p1.name = 'egon'
    # print(p1.__dict__)

     

  • 类的装饰器
  • 装饰器也可以装饰类

  • def deco(obj):
        print('-------', obj)
        obj.x = 1
        obj.y = 2
        obj.z = 3
        return obj
    
    # @deco    #等价于test=deco(test),将test值传给deco
    # def test():
    #     print('test函数运行')
    #
    # test()
    
    @deco  # Foo=deco(Foo),类的装饰器,将类传给装饰器的函数,返回值作为新类。以后再运行Foo,就是被deco处理过的Foo
    class Foo:
        pass
    
    print(Foo.__dict__)
    # 目的:用同一个装饰器,为不同类增加不同的属性
    def Typed(**kwargs):
        def deco(obj):
            # print('-->', kwargs)
            # print('类名-->', obj)
            for key, val in kwargs.items():
                setattr(obj, key, val)
            return obj
    
        # print('==>', kwargs)
        return deco
    
    
    @Typed(x=1, y=2, z=3)  # 步骤一:Typed()本身会执行一遍,返回deco。步骤二,@deco
    class Foo:
        pass
    
    print(Foo.__dict__)
    
    
    @Typed(name='egon')
    class Bar:
        pass
    
    print(Bar.name)

     

  • 装饰器的应用
  • # 用装饰器来实现类属性被描述符代理,以实现针对传入值的类型检查
    class Typed:
        def __init__(self, key, expected_type):
            self.key = key
            self.expected_type = expected_type
    
        def __get__(self, instance, owner):  # instance是实例本身,owner是实例的拥有者,即类名
            print('这是get方法')
            return instance.__dict__[self.key]  # 返回实例字典中的值
    
        def __set__(self, instance, value):
            print('set方法')
            if not isinstance(value, self.expected_type):
                raise TypeError('%s 传入的类型不是%s' % (self.key, self.expected_type))
            instance.__dict__[self.key] = value
    
        def __delete__(self, instance):
            print('delete方法')
            # print('instance参数【%s】' % instance)
            instance.__dict__.pop(self.key)
    
    
    def deco(**kwargs):
        def wrapper(obj):
            for key, val in kwargs.items():
                # print('==>', key, val)
                setattr(obj, key, Typed(key, val))  # Typed(key,val),给类增加一个类属性,该类属性被描述符代理
                                                    # 所以key的value不是简单的value,而不是描述符
            return obj
    
        return wrapper
    
    
    @deco(name=str, age=int, salary=float)
    class People:
        def __init__(self, name, age, salary):
            self.name = name
            self.age = age
            self.salary = salary
    
    
    # p1 = People('alex', 13, 13.3)
    p1 = People('122', 13, 13.3)
    print(p1.__dict__) 
  • 自定制property
  • @property,所有的@都是执行,将函数传入property执行,返回值作为新函数
  • #自定制property
    class Lazyproperty:
        def __init__(self, func):
            print('====>', func)
            self.func = func
    
        def __get__(self, instance, owner):
            res = self.func(instance)#此步运行area方法,area方法就是property类实例化的self实例
            return res
    
    class Room:
    
        def __init__(self, name, width, length):
            self.name = name
            self.width = width
            self.length = length
    
        @Lazyproperty  # 实现了给类增加描述符的功能
        def area(self):
            return self.width * self.length
    
    r1 = Room('厕所', 1, 1)
    print(r1.area) 
  • #同上页的描述符的第二种方式
    class Foo:
        @property#前提,必须先定义此,方可定义后边
        def AAA(self):
            print('get的时候运行我')
    
        @AAA.setter#给AAA赋值时,触发此函数
        def AAA(self,val):
            print('set的时候运行我',val)
    
        @AAA.deleter#删除AAA时执行此操作
        def AAA(self):
            print('del的时候运行我')
    
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
  • 元类

  • 产生类的类,就是type
  • 元类的实例是类,正如类的实例是对象
  • #另外一种产生实例的方法
    def __init__(self,name,age):#定义类中的init方法
        self.name=name
        self.age=age
    
    def test(self):
        pass
    
    FFo=type('FFo',(object,),{'x':1,'__init__':__init__,'test':test})#定义类
    print(FFo)
    print(FFo.__dict__)
    
    f1=FFo('alex',18)#实例化
    print(f1.name)
  • 自定义元类,控制类的生成过程

  • #自定义元类
    class MyType(type):
        def __init__(self, a, b, c):
            print('元类的构造函数执行')
            print(self)#self是产生的类Foo
            print(a)
            print(b)
            print(c)
    
        def __call__(self, *args, **kwargs):
            print('=====')
            obj = object.__new__(self)  # object.__new__(Foo),即Foo产生一个新对象
            self.__init__(obj, *args, **kwargs)  # Foo.__init__()
                                                #此处的self.__init__方法,就是在执行Foo中的init方法
    
    
    class Foo(metaclass=MyType):  # MyType(self,'Foo',(object),{}),使用元类创建一个类Foo
        # MyType(4个参数)--》__init__
        def __init__(self, name):
            self.name = name
    
    
    f1 = Foo('name')  # 执行Foo方法就是在调用父类的call方法
这篇关于python基础14-__enter__/__exit__/描述符管理实例的实参类型控制/类的装饰器/自定制property/自定义元类的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!