Day 28 类的用法延伸
###上下文管理协议,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法,即在类中添加__enter__, __exit__方法
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
# return True
with Open('a.txt') as f: #Open('a.txt’)相当于对象实例化,with Open('a.txt') 触发__enter__运行,__enter__的返回值赋值给f
print('=====>执行代码块')
print(f.xxxxx) #当执行不存在的,触发__exit__,若return True则吞掉异常,若return值不为True则吐出异常
__exit__的运行完毕就代表了整个with语句的执行完毕
###实现控制实例化数据类型
class Type:
def __init__(self,key,expected_type):
self.key=key
self.expected_type=expected_type
def __get__(self, instance, owner):
print("触发get")
return instance.__dict__[self.key]
def __set__(self, instance, value): #此处的self是Type对应的实例,instance是People对应的实例
print("触发set")
if not isinstance(value,self.expected_type):
raise TypeError
instance.__dict__[self.key]=value
def __delete__(self, instance):
print('触发delete')
instance.__dict__.pop(self.key)
class People:
name=Type('name',str)
age=Type('age',int)
def __init__(self,name,age):
self.name=name
self.age=age
p1=People("xyy",19) #触发set
print(p1.name)
print(p1.__dict__)
del p1.name
#####类的装饰器的基本原理
def deco(obj):
obj.x=1
obj.y=2
obj.z=3
return obj
@deco # Foo=deco(Foo)
class Foo:
pass
print(Foo.__dict__) # 查看x,y,z
####用类装饰器按不同的类里添加属性
def Typed(**kwargs):
def deco(obj):
print("------------->",kwargs)
for key,val in kwargs.items():
setattr(obj,key,val)
return obj
print("==============>",kwargs)
return deco
@Typed(x=1,y=2,z=3) # @Typed(x=1,y=2,z=3)>>>@deco
class Foo:
pass
print(Foo.__dict__) #查看x,y,z
@Typed(name="xyy")
class Bar:
pass
print(Bar.__dict__)
################
######装饰器是函数时
class Room:
def __init__(self,length,width,hight):
self.length=length
self.width=width
self.hight=hight
@property #area=property(area)相当于给类添加数据属性
def area(self):
return self.width*self.length
@property
def v(self):
return self.area*self.hight
r1=Room(2,3,5)
print(r1.area)
print(r1.v)
print(Room.__dict__)#查看area,v
######装饰器是类时,自定制(模拟)property
class Diyproperty:
def __init__(self,func):
print("-------->执行Diyproperty",func)
self.func=func
def __get__(self, instance, owner):
print("---->触发get")
res=self.func(instance)
return res
class Room:
"""在类Diyproperty里添加get属性,@Diyproperty即相当于描述符
area=Diyproperty(area),因此func=area"""
def __init__(self,length,width,hight):
self.length=length
self.width=width
self.hight=hight
@Diyproperty #area=Diyproperty(area)相当于实例化,触发Diyproperty的__init__的运行。同时相当于给Room类添加数据属性,在Room的数学字典里key:"area" 对应value:"Diyproperty(area)"
def area(self):
print("-------执行area")
return self.width*self.length
@Diyproperty
def volume(self):
print("-------执行volume")
return self.area*self.hight
r1=Room(2,3,5)
# print("面积是:",r1.area)
# print(r1.area.func(r1)) #手动运行,最好不这么做
print("体积是:",r1.volume) #触发描述符的__get__方法
# print(Room.__dict__) #查看area,v
##############解决用类调用描述符的__get__方法时返回None的问题
class Diyproperty:
def __init__(self,func):
print("-------->执行Diyproperty",func)
self.func=func
def __get__(self, instance, owner):
print("---->触发get")
if instance is None: #用类调用描述符触发
return self
res = self.func(instance)
return res
class Room:
"""在类Diyproperty里添加get属性,@Diyproperty即相当于描述符
area=Diyproperty(area),因此func=area"""
def __init__(self,length,width,hight):
self.length=length
self.width=width
self.hight=hight
@Diyproperty #area=Diyproperty(area)相当于实例化,触发Diyproperty的__init__的运行。同时相当于给Room类添加数据属性,在Room的数学字典里key:"area" 对应value:"Diyproperty(area)"
def area(self):
print("-------执行area")
return self.width*self.length
r1=Room(2,3,5)
print(Room.area) #当类调用描述符的__get__属性时返回None。故需用if instance is None:进行判断
#########关于property的补充
#第一种方法
class Foo:
@property
def AAA(self):
print("执行AAA")
@AAA.setter
def AAA(self,val):
print("执行set")
@AAA.deleter
def AAA(self):
print("执行delete")
p1=Foo()
p1.AAA="xyy"
print(p1.__dict__)
# del p1.AAA
#第二种方法
class Foo:
def get_AAA(self):
print("执行get")
def set_AAA(self,val):
print("执行set",val)
def del_AAA(self):
print("执行delete")
AAA=property(get_AAA,set_AAA,del_AAA) #顺序不能变,此处property相当于做了一件描述符的事
p1=Foo()
p1.AAA
p1.AAA="xyy"
print(p1.__dict__)
del p1.AAA
>>>
执行get
执行set xyy
{}
执行delete
######元类
元类的实例为类,类的实例为对象
type是python的一个内建元类
两种定义类的方式:
class定义类
type('类名',(object,),{key1:value1,})
声明元类:metaclass=type
#########自定制元类,查看参数
class DiyType(type):
def __init__(self,a,b,c):
print("元类的构造函数执行")
print(a)
print(b)
print(c)
class Foo(metaclass=DiyType): #DiyType(Foo,’Foo’,(),{}),触发DiyType的init运行返回结果Foo
"""metaclass用来声明元类"""
def __init__(self,name):
self.name=name
>>>
元类的构造函数执行
Foo
()
{'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x11434b1e0>}
###上下文管理协议,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法,即在类中添加__enter__, __exit__方法
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
# return True
with Open('a.txt') as f: #Open('a.txt’)相当于对象实例化,with Open('a.txt') 触发__enter__运行,__enter__的返回值赋值给f
print('=====>执行代码块')
print(f.xxxxx) #当执行不存在的,触发__exit__,若return True则吞掉异常,若return值不为True则吐出异常
__exit__的运行完毕就代表了整个with语句的执行完毕
###实现控制实例化数据类型
class Type:
def __init__(self,key,expected_type):
self.key=key
self.expected_type=expected_type
def __get__(self, instance, owner):
print("触发get")
return instance.__dict__[self.key]
def __set__(self, instance, value): #此处的self是Type对应的实例,instance是People对应的实例
print("触发set")
if not isinstance(value,self.expected_type):
raise TypeError
instance.__dict__[self.key]=value
def __delete__(self, instance):
print('触发delete')
instance.__dict__.pop(self.key)
class People:
name=Type('name',str)
age=Type('age',int)
def __init__(self,name,age):
self.name=name
self.age=age
p1=People("xyy",19) #触发set
print(p1.name)
print(p1.__dict__)
del p1.name
#####类的装饰器的基本原理
def deco(obj):
obj.x=1
obj.y=2
obj.z=3
return obj
@deco # Foo=deco(Foo)
class Foo:
pass
print(Foo.__dict__) # 查看x,y,z
####用类装饰器按不同的类里添加属性
def Typed(**kwargs):
def deco(obj):
print("------------->",kwargs)
for key,val in kwargs.items():
setattr(obj,key,val)
return obj
print("==============>",kwargs)
return deco
@Typed(x=1,y=2,z=3) # @Typed(x=1,y=2,z=3)>>>@deco
class Foo:
pass
print(Foo.__dict__) #查看x,y,z
@Typed(name="xyy")
class Bar:
pass
print(Bar.__dict__)
################
######装饰器是函数时
class Room:
def __init__(self,length,width,hight):
self.length=length
self.width=width
self.hight=hight
@property #area=property(area)相当于给类添加数据属性
def area(self):
return self.width*self.length
@property
def v(self):
return self.area*self.hight
r1=Room(2,3,5)
print(r1.area)
print(r1.v)
print(Room.__dict__)#查看area,v
######装饰器是类时,自定制(模拟)property
class Diyproperty:
def __init__(self,func):
print("-------->执行Diyproperty",func)
self.func=func
def __get__(self, instance, owner):
print("---->触发get")
res=self.func(instance)
return res
class Room:
"""在类Diyproperty里添加get属性,@Diyproperty即相当于描述符
area=Diyproperty(area),因此func=area"""
def __init__(self,length,width,hight):
self.length=length
self.width=width
self.hight=hight
@Diyproperty #area=Diyproperty(area)相当于实例化,触发Diyproperty的__init__的运行。同时相当于给Room类添加数据属性,在Room的数学字典里key:"area" 对应value:"Diyproperty(area)"
def area(self):
print("-------执行area")
return self.width*self.length
@Diyproperty
def volume(self):
print("-------执行volume")
return self.area*self.hight
r1=Room(2,3,5)
# print("面积是:",r1.area)
# print(r1.area.func(r1)) #手动运行,最好不这么做
print("体积是:",r1.volume) #触发描述符的__get__方法
# print(Room.__dict__) #查看area,v
##############解决用类调用描述符的__get__方法时返回None的问题
class Diyproperty:
def __init__(self,func):
print("-------->执行Diyproperty",func)
self.func=func
def __get__(self, instance, owner):
print("---->触发get")
if instance is None: #用类调用描述符触发
return self
res = self.func(instance)
return res
class Room:
"""在类Diyproperty里添加get属性,@Diyproperty即相当于描述符
area=Diyproperty(area),因此func=area"""
def __init__(self,length,width,hight):
self.length=length
self.width=width
self.hight=hight
@Diyproperty #area=Diyproperty(area)相当于实例化,触发Diyproperty的__init__的运行。同时相当于给Room类添加数据属性,在Room的数学字典里key:"area" 对应value:"Diyproperty(area)"
def area(self):
print("-------执行area")
return self.width*self.length
r1=Room(2,3,5)
print(Room.area) #当类调用描述符的__get__属性时返回None。故需用if instance is None:进行判断
#########关于property的补充
#第一种方法
class Foo:
@property
def AAA(self):
print("执行AAA")
@AAA.setter
def AAA(self,val):
print("执行set")
@AAA.deleter
def AAA(self):
print("执行delete")
p1=Foo()
p1.AAA="xyy"
print(p1.__dict__)
# del p1.AAA
#第二种方法
class Foo:
def get_AAA(self):
print("执行get")
def set_AAA(self,val):
print("执行set",val)
def del_AAA(self):
print("执行delete")
AAA=property(get_AAA,set_AAA,del_AAA) #顺序不能变,此处property相当于做了一件描述符的事
p1=Foo()
p1.AAA
p1.AAA="xyy"
print(p1.__dict__)
del p1.AAA
>>>
执行get
执行set xyy
{}
执行delete
######元类
元类的实例为类,类的实例为对象
type是python的一个内建元类
两种定义类的方式:
class定义类
type('类名',(object,),{key1:value1,})
声明元类:metaclass=type
#########自定制元类,查看参数
class DiyType(type):
def __init__(self,a,b,c):
print("元类的构造函数执行")
print(a)
print(b)
print(c)
class Foo(metaclass=DiyType): #DiyType(Foo,’Foo’,(),{}),触发DiyType的init运行返回结果Foo
"""metaclass用来声明元类"""
def __init__(self,name):
self.name=name
>>>
元类的构造函数执行
Foo
()
{'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x11434b1e0>}