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): #此处的selfType对应的实例,instancePeople对应的实例

        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__)#查看areav

######装饰器是类时,自定制(模拟)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__)   #查看areav

##############解决用类调用描述符的__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’,(),{}),触发DiyTypeinit运行返回结果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): #此处的selfType对应的实例,instancePeople对应的实例

        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__)#查看areav

######装饰器是类时,自定制(模拟)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__)   #查看areav

##############解决用类调用描述符的__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’,(),{}),触发DiyTypeinit运行返回结果Foo

    """metaclass用来声明元类"""

    def __init__(self,name):

        self.name=name

 

>>>

元类的构造函数执行

Foo

()

{'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x11434b1e0>}

 

posted on 2019-10-12 18:49  进击的许盈盈  阅读(93)  评论(0编辑  收藏  举报