python 描述符 上下文管理协议 类装饰器 property metaclass

Posted 风追海浪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

以上是关于python 描述符 上下文管理协议 类装饰器 property metaclass的主要内容,如果未能解决你的问题,请参考以下文章

python(描述符应用与类的装饰器)

Python之路:描述符,类装饰器,元类

19 描述符应用 与类的装饰器

杂项之python描述符协议

在 Python 中充当装饰器和上下文管理器的函数?

32.Python面向对象描述符运算符底层装饰器:闭包-闭包参数-内置装饰器-类装饰器