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

时间:2023-03-09 06:03:43
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