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的主要内容,如果未能解决你的问题,请参考以下文章