zoukankan      html  css  js  c++  java
  • python 描述符 上下文管理协议 类装饰器 property metaclass

    1.描述符

    #!/usr/bin/python env
    # coding=utf-8
    # 数据描述符__get__ __set__ __delete__
    '''
    描述符总结
    描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性
    描述符是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件

    注意事项:
    一 描述符本身应该定义成新式类,被代理的类也应该是新式类
    二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
    三 要严格遵循该优先级,优先级由高到底分别是
    1.类属性
    2.数据描述符
    3.实例属性
    4.非数据描述符
    5.找不到的属性触发__getattr__()
    描述符分2种 1.数据描述符:至少有get set方法 2.非数据描述符:没有set方法
    ''' class Str: def __init__(self, name,val_type): self.name = name self.val_type = val_type # instance 实例对象 owner实例的类 def __get__(self, instance, owner): print('get方法', instance, owner) return instance.__dict__[self.name] # instance 实例对象 value实例的值 def __set__(self, instance, value): print('set方法', instance, value) if not isinstance(value, self.val_type): raise TypeError("%s 的数据类型不是 %s" % (value, self.val_type)) instance.__dict__[self.name] = value def __delete__(self, instance): print('delete方法', instance) instance.__dict__.pop(self.name) class People: # 描述符 name = Str('name', str) age = Str('age', int) salary = Str('salary', int) def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary p1 = People('wangwu', 12, 98921) # 调用 print(p1.__dict__) # print(p1) # p1.name # #赋值 # print(p1.__dict__) # p1.name='egonlin' # print(p1.__dict__) # # #删除 # print(p1.__dict__) # del p1.name # print(p1.__dict__)

    2.上下文管理协议

    操作文件对象写法

    1 with open('a.txt') as f:
    2   '代码块'

    上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

    # 上下文管理协议 with
    '''
    # with open('filename') as f:
    #     代码块
    1.with.obj ---> obj.__enter__(), return val
    2.as f ----> f=val
    3.with obj as f === f=obj.__enter()
    4.执行
    1)没有异常时,all code运行后,__exit__ 三个参数都为None
    2)有异常时,从异常的的位置触发__exit__
       a。如果exit的返回值为True,吞掉了异常
       b.反之,抛出异常
       c.exit的代码执行完毕代表了整个with语句执行完毕
    '''
    class Foo:
        def __init__(self, name):
            self.name = name
    
        def __enter__(self):  # 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
            return self
    
        # exc_type 异常类:NameError
    # exc_val 异常值:name 'abc异常abc' is not defined
    # exc_tb 追踪信息: Traceback后面的内容
    # Traceback(most recent call last): # NameError: name 'abc异常abc' is not defined def __exit__(self, exc_type, exc_val, exc_tb): # with里有异常时 触发改函数 print("%s %s %s" % (exc_type, exc_val, exc_tb)) return True # 如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行 with Foo('a.txt') as f: print(f) # print(abc异常abc) print(f.name) print("*"*100)
    # 上下文管理实例
    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__处理

    3.类装饰器

    # 函数装饰器范式
    # def wrap(func):
    #     def wrapper(*args, **kwargs):
    #         func(*args, **kwargs)
    #         return True
    #     return wrapper
    
    # 无参类装饰器范式
    # def wrap(cls):
    #     return cls
    
    # 有参类装饰器范式
    # def wrap(**kwargs):
    #     def wrapper(obj):
    #         # 操作kwargs
    #         return obj
    #     return wrapper
    
    # 有参类装饰器
    class Check_type:
        def __init__(self, name, val_type):
            self.name = name
            self.val_type = val_type
    
        # instance 实例对象 owner实例的类
        def __get__(self, instance, owner):
            # print('get方法', instance, owner)
            return instance.__dict__[self.name]
    
        # instance 实例对象 value实例的值
        def __set__(self, instance, value):
            # print('set方法', instance, value)
            if not isinstance(value, self.val_type):
                raise TypeError("%s的数据类型不是 %s" % (value, self.val_type))
            instance.__dict__[self.name] = value
    
        def __delete__(self, instance):
            # print('delete方法', instance)
            instance.__dict__.pop(self.name)
    
    
    def Typed(**kwargs):  # kwargs ===> name=str, age= int, salary=int
        def wrapper(obj):
            for key, val in kwargs.items():
                # 描述符 val是key的类型
                # val = Check_type('val', str)
                setattr(obj, key, Check_type(key, val))
            return obj
        return wrapper
    
    @Typed(y=2, x=1, z=3)
    class Foo:
        pass
    
    @Typed(name='wangwu')
    class foo:
        pass
    
    @Typed(name=str, age=int, salary=int)  # @warpper -->People=warper(people)
    class People:
        # 描述符
        # name = Str('name', str)
        # age = Str('age', int)
        # salary = Str('salary', int)
        def __init__(self, name, age, salary):
            self.name = name
            self.age = age
            self.salary = salary
    
    
    print(People.__dict__)
    p1 = People('wangwu', "d", 98921)
    
    
    # 调用
    print(p1.__dict__)

    4.仿property

    # 类装饰器
    # class Cls_property:
    #     def __init__(self,func):
    #         self.func = func
    # 仿property类装饰器
    
    
    class Cls_property:
        def __init__(self, func):
            # print("func属性 %s " %(func))
            self.func = func
    
        # 描述get有两个参数 第一个是实例 第二个是类
        def __get__(self, instance, owner):
            # val = self.func()
            print('get---->')
            print('instance: %s' % instance)  # 实例对象 r1
            print('owner: %s' % owner)  # 类 Room
            if instance is None:
                return self
            res = self.func(instance)
            # property延时计算
            setattr(instance, self.func.__name__, res)
            return res
        # 加上set 数据描述符
        # def __set__(self, instance, value):
        #     pass
    
    
    class Room:
        tag = 168
    
        def __init__(self, owner, width, length):
            self.owner = owner
            self.width = width
            self.length = length
    
        # @cls_property
        @Cls_property  # area=property(area)
        def area(self):
            return self.width * self.length
    
        # @cls_property
        @property  # area=property(area)
        def area1(self):
            return self.width * self.length
    
        # 类方法 能访问类的属性不能访问实例属性
        @classmethod
        def test_tag(cls, x):
            print(cls)
            print("from test_tag %s %s" % (cls.tag, x))
    
        # 静态方法  不能访问类、实例属性
        @staticmethod
        def action(a, b, c):
            print("%s %s %s" % (a, b, c))
    
        # 类可以调用,实例不可调用test
        def test(cls, x):
            print(cls)
            print("from test_tag %s %s" % (cls.tag, x))
    
        @property  # <property object at 0x01FE80F0>
        def pro_test(self):
            return "pro_test"
    
    
    r1 = Room('zq', 1, 100)
    print(r1.__dict__)  # 没找到area属性值 那就调用代理的Roo的area值
    print(r1.area)
    print(r1.__dict__)  # 没找到area属性值 那就调用代理的Roo的area值
    print(r1.area)
    print(r1.area)
    print(r1.area)
    # print(Room.__dict__['area'])
    
    # print(Room.area)
    # print(Room.pro_test)
    
    # 一个静态属性property本质就是实现了get,set,delete三种方法
    # 方法一
    class Foo:
        @property
        def AAA(self):
            print('get的时候运行我啊')
    
        @AAA.setter
        def AAA(self,value):
            print('set的时候运行我啊', value)
    
        @AAA.deleter
        def AAA(self):
            print('delete的时候运行我啊')
    
    #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA
    print("<----------------------->")
    
    # 方法二
    class Foo:
        def get_AAA(self):
            print('get的时候运行我啊')
    
        def set_AAA(self,value):
            print('set的时候运行我啊', value)
    
        def delete_AAA(self):
            print('delete的时候运行我啊')
        AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
    
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA

    5.元类 metaclass

    元类是类的类,是类的模板

    元类的实例是类,类的实例是 对象

    type是python的一个内建元类 ,用来控制生成类,python中任何class定义的类其实都是type类实例化的对象

    # 创建类有2种方法
    # metaclass
    # 类的默认元类是type
    # 1.
    class Foo:
        pass
    # tpye(str)
    t = type(Foo)
    print(t)
    # print(t.__dict__)
    
    def test(self):
        pass
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    # s三个参数 类名 (父类,), {属性字典}
    # 2.type(类名,(object,),{})
    t = type('t', (object,), {'a': 1, '__init__': __init__, 'test': test})
    print(t.__dict__)  # {'a': 1, '__weakref__': <attribute '__weakref__' of 't' objects>, '__init__': <function __init__ at 0x002C4738>, '__module__': '__main__', 'test': <function test at 0x00703660>, '__doc__': None, '__dict__': <attribute '__dict__' of 't' objects>}
    print(t)  # <class '__main__.t'>
    print("------------------------->")
    
    
    # 自定义元类
    class Mytype(type):
        def __init__(self, *args, **kwargs):
            print("元类的自定义类")
            # for i in args:
            #     print(i)
    
        def __call__(self, *args, **kwargs):  # self == Foo
            # print("__call__函数:",self)
            obj = object.__new__(self)  # object.__nee__(Foo) --> 产生 f1 产生实例obj
            # print("obj产生: ",obj)
            self.__init__(obj, *args, **kwargs)  # Foo.__init__()
            return obj
    
    
    class Foo(metaclass=Mytype):  # Mytype(传了4个参数: self,Foo,(),{})-->触发mytype __init__
        def __init__(self, name):
            self.name = name  # f1.name = name
    
    
    print(Foo)
    f1 = Foo('wangwu')
    print(f1)
    # print(f1.__dict__)

    参考:http://www.cnblogs.com/linhaifeng/articles/6204014.html#_label15

  • 相关阅读:
    Android与WebView的插件管理机制
    在mac下搭建Apacheserver
    “懒”也要有境地---大部分程序猿都在的地方,再不来就out了。
    codeforces Looksery Cup 2015 H Degenerate Matrix
    HDU 1247 Hat’s Words(字典树变形)
    SICP 习题 (1.38)解题总结
    scikit-learn:4.2. Feature extraction(特征提取,不是特征选择)
    iOS_高效开发之道
    亚马逊2014在线面试第一题
    通过AO连接多个EO并进行使用
  • 原文地址:https://www.cnblogs.com/icemonkey/p/10459477.html
Copyright © 2011-2022 走看看