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

__enter__和__exit__

数据描述符:至少实现__get__,__set__方法的

非数据描述符:没有__set__方法的

上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。

# -*- coding: utf-8 -*-
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中代码块执行完毕时执行我啊‘)


with Open(‘b.txt‘) as f:
    print(‘=====>执行代码块‘)
    # print(f,f.name)
# -*- coding: utf-8 -*-
class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘)

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(‘with中代码块执行完毕时执行我啊‘)
        #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行
        print(exc_type) #异常类型
        print(exc_val)  #异常值
        print(exc_tb)   #追溯信息

with Open(‘b.txt‘) as f:    #触发__enter__
    print(‘=====>执行代码块‘)
    raise AttributeError(‘***着火啦,救火啊***‘)
print(‘0‘*100)      #------->不会执行

用途:

1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制

描述符应用

控制输入类型

# -*- coding: utf-8 -*-
class Typed:
    def __init__(self,key):
        self.key=key

    def __get__(self,instance,owner):
        print(‘get方法‘)
        # print(‘isinstance参数;‘,isinstance)
        # print(‘owner参数;‘,owner)
        return instance.__dict__[self.key]

    def __set__(self,instance,value):
        print(‘set方法‘)
        # print(‘isinstance参数;‘,instance)
        # print(‘owner参数;‘,value)
        #通过初始化函数写活了
        if not isinstance(value,str):
            print(‘输入不是字符串‘)
        else:
            instance.__dict__[self.key]=value

    def __delete__(self,instance):
            print(‘delete方法‘)
            # print(‘isinstance参数;‘, instance)
            instance.__dict__.pop(self.key)


class people:
    name=Typed(‘name‘)
    # age=Typed(‘age‘)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

p1=people("bob",22,5000)
p1.name
print(p1.__dict__)  #没有name属性,他被数据描述符代理了
del p1.name
print(p1.__dict__)
p2=people(1,22,5000)

进一步改进

# -*- coding: utf-8 -*-
class Typed:
    def __init__(self,key,expected_type):
        self.key=key
        self.expected_type=expected_type

    def __get__(self,instance,owner):
        # print(‘get方法‘)
        # print(‘isinstance参数;‘,isinstance)
        # print(‘owner参数;‘,owner)
        return instance.__dict__[self.key]

    def __set__(self,instance,value):
        # print(‘set方法‘)
        # print(‘isinstance参数;‘,instance)
        # print(‘owner参数;‘,value)
        #通过初始化函数写活了
        if not isinstance(value,self.expected_type):
            print(‘输入不是%s‘%self.expected_type)
        else:
            instance.__dict__[self.key]=value

    def __delete__(self,instance):
            print(‘delete方法‘)
            # print(‘isinstance参数;‘, instance)
            instance.__dict__.pop(self.key)


class people:
    name=Typed(‘name‘,str)
    age=Typed(‘age‘,int)
    salary=Typed(‘salary‘,float)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

p1=people("bob",22,5000.0)
p1.name
print(p1.__dict__)  #没有name属性,他被数据描述符代理了
del p1.name
print(p1.__dict__)
p2=people(1,22,5000.0)

 类的装饰器

初级(没有参数):

# -*- coding: utf-8 -*-
def decorate(cls):
    print(‘类的装饰器开始运行啦------>‘)
    return cls

@decorate       #无参:People=decorate(People)
class People:
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary
        print(self.age,self.name,self.salary)

p1=People(‘egon‘,18,3333.3)    

------------恢复内容开始------------

__enter__和__exit__

数据描述符:至少实现__get__,__set__方法的

非数据描述符:没有__set__方法的

上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。

# -*- coding: utf-8 -*-
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中代码块执行完毕时执行我啊‘)


with Open(‘b.txt‘) as f:
    print(‘=====>执行代码块‘)
    # print(f,f.name)
# -*- coding: utf-8 -*-
class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘)

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(‘with中代码块执行完毕时执行我啊‘)
        #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行
        print(exc_type) #异常类型
        print(exc_val)  #异常值
        print(exc_tb)   #追溯信息

with Open(‘b.txt‘) as f:    #触发__enter__
    print(‘=====>执行代码块‘)
    raise AttributeError(‘***着火啦,救火啊***‘)
print(‘0‘*100)      #------->不会执行

用途:

1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制

描述符应用

控制输入类型

# -*- coding: utf-8 -*-
class Typed:
    def __init__(self,key):
        self.key=key

    def __get__(self,instance,owner):
        print(‘get方法‘)
        # print(‘isinstance参数;‘,isinstance)
        # print(‘owner参数;‘,owner)
        return instance.__dict__[self.key]

    def __set__(self,instance,value):
        print(‘set方法‘)
        # print(‘isinstance参数;‘,instance)
        # print(‘owner参数;‘,value)
        #通过初始化函数写活了
        if not isinstance(value,str):
            print(‘输入不是字符串‘)
        else:
            instance.__dict__[self.key]=value

    def __delete__(self,instance):
            print(‘delete方法‘)
            # print(‘isinstance参数;‘, instance)
            instance.__dict__.pop(self.key)


class people:
    name=Typed(‘name‘)
    # age=Typed(‘age‘)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

p1=people("bob",22,5000)
p1.name
print(p1.__dict__)  #没有name属性,他被数据描述符代理了
del p1.name
print(p1.__dict__)
p2=people(1,22,5000)

进一步改进

# -*- coding: utf-8 -*-
class Typed:
    def __init__(self,key,expected_type):
        self.key=key
        self.expected_type=expected_type

    def __get__(self,instance,owner):
        # print(‘get方法‘)
        # print(‘isinstance参数;‘,isinstance)
        # print(‘owner参数;‘,owner)
        return instance.__dict__[self.key]

    def __set__(self,instance,value):
        # print(‘set方法‘)
        # print(‘isinstance参数;‘,instance)
        # print(‘owner参数;‘,value)
        #通过初始化函数写活了
        if not isinstance(value,self.expected_type):
            print(‘输入不是%s‘%self.expected_type)
        else:
            instance.__dict__[self.key]=value

    def __delete__(self,instance):
            print(‘delete方法‘)
            # print(‘isinstance参数;‘, instance)
            instance.__dict__.pop(self.key)


class people:
    name=Typed(‘name‘,str)
    age=Typed(‘age‘,int)
    salary=Typed(‘salary‘,float)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

p1=people("bob",22,5000.0)
p1.name
print(p1.__dict__)  #没有name属性,他被数据描述符代理了
del p1.name
print(p1.__dict__)
p2=people(1,22,5000.0)

 类的装饰器

初级(没有参数):

# -*- coding: utf-8 -*-
def decorate(cls):
    print(‘类的装饰器开始运行啦------>‘)
    return cls

@decorate       #无参:People=decorate(People)
class People:
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary
        print(self.age,self.name,self.salary)

p1=People(‘egon‘,18,3333.3)    

------------恢复内容开始------------

__enter__和__exit__

数据描述符:至少实现__get__,__set__方法的

非数据描述符:没有__set__方法的

上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。

# -*- coding: utf-8 -*-
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中代码块执行完毕时执行我啊‘)


with Open(‘b.txt‘) as f:
    print(‘=====>执行代码块‘)
    # print(f,f.name)
# -*- coding: utf-8 -*-
class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘)

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(‘with中代码块执行完毕时执行我啊‘)
        #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行
        print(exc_type) #异常类型
        print(exc_val)  #异常值
        print(exc_tb)   #追溯信息

with Open(‘b.txt‘) as f:    #触发__enter__
    print(‘=====>执行代码块‘)
    raise AttributeError(‘***着火啦,救火啊***‘)
print(‘0‘*100)      #------->不会执行

用途:

1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制

描述符应用

控制输入类型

# -*- coding: utf-8 -*-
class Typed:
    def __init__(self,key):
        self.key=key

    def __get__(self,instance,owner):
        print(‘get方法‘)
        # print(‘isinstance参数;‘,isinstance)
        # print(‘owner参数;‘,owner)
        return instance.__dict__[self.key]

    def __set__(self,instance,value):
        print(‘set方法‘)
        # print(‘isinstance参数;‘,instance)
        # print(‘owner参数;‘,value)
        #通过初始化函数写活了
        if not isinstance(value,str):
            print(‘输入不是字符串‘)
        else:
            instance.__dict__[self.key]=value

    def __delete__(self,instance):
            print(‘delete方法‘)
            # print(‘isinstance参数;‘, instance)
            instance.__dict__.pop(self.key)


class people:
    name=Typed(‘name‘)
    # age=Typed(‘age‘)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

p1=people("bob",22,5000)
p1.name
print(p1.__dict__)  #没有name属性,他被数据描述符代理了
del p1.name
print(p1.__dict__)
p2=people(1,22,5000)

进一步改进

# -*- coding: utf-8 -*-
class Typed:
    def __init__(self,key,expected_type):
        self.key=key
        self.expected_type=expected_type

    def __get__(self,instance,owner):
        # print(‘get方法‘)
        # print(‘isinstance参数;‘,isinstance)
        # print(‘owner参数;‘,owner)
        return instance.__dict__[self.key]

    def __set__(self,instance,value):
        # print(‘set方法‘)
        # print(‘isinstance参数;‘,instance)
        # print(‘owner参数;‘,value)
        #通过初始化函数写活了
        if not isinstance(value,self.expected_type):
            print(‘输入不是%s‘%self.expected_type)
        else:
            instance.__dict__[self.key]=value

    def __delete__(self,instance):
            print(‘delete方法‘)
            # print(‘isinstance参数;‘, instance)
            instance.__dict__.pop(self.key)


class people:
    name=Typed(‘name‘,str)
    age=Typed(‘age‘,int)
    salary=Typed(‘salary‘,float)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

p1=people("bob",22,5000.0)
p1.name
print(p1.__dict__)  #没有name属性,他被数据描述符代理了
del p1.name
print(p1.__dict__)
p2=people(1,22,5000.0)

 类的装饰器

初级(没有参数):

# -*- coding: utf-8 -*-
def decorate(cls):
    print(‘类的装饰器开始运行啦------>‘)
    return cls

@decorate       #无参:People=decorate(People)
class People:
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary
        print(self.age,self.name,self.salary)

p1=People(‘egon‘,18,3333.3)    

进阶(有参数)

# -*- coding: utf-8 -*-
def typeassert(**kwargs):

    def decorate(cls):
        print(‘2------>‘)
        for key,value in kwargs.items():
            setattr(cls,key,value)
        return cls
    print(‘1------>‘, kwargs)
    return decorate
@typeassert()   #name=str,age=int,salary=float
#有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
class People:
    pass
    # def __init__(self,name,age,salary):
    #     self.name=name
    #     self.age=age
    #     self.salary=salary

print(People.__dict__)

@typeassert(hobby=‘ball‘)
class bar():
    pass#添加了hobby属性
print(bar.__dict__)

 可添加不定个数属性的示例:

# -*- coding: utf-8 -*-
class Typed:
    def __init__(self,name,expected_type):
        self.name=name
        self.expected_type=expected_type
    def __get__(self, instance, owner):
        print(‘get--->‘,instance,owner)
        if instance is None:
            return self
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        print(‘set--->‘,instance,value)
        if not isinstance(value,self.expected_type):
            raise TypeError(‘Expected %s‘ %str(self.expected_type))
        instance.__dict__[self.name]=value
    def __delete__(self, instance):
        print(‘delete--->‘,instance)
        instance.__dict__.pop(self.name)

def typeassert(**kwargs):
    def decorate(cls):
        print(‘类的装饰器开始运行啦------>‘,kwargs)
        for name,expected_type in kwargs.items():
            setattr(cls,name,Typed(name,expected_type))
        return cls
    return decorate

@typeassert(name=str,age=int,salary=float)#在此添加要增加的属性
#有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
class People:
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

print(People.__dict__)
p1=People(‘egon‘,18,3333.3)  

自定制property

装饰器可以是函数,也可以是类类型。

# -*- coding: utf-8 -*-
class Lazyproperty:
    def __init__(self,func):
        self.func=func
    def __get__(self, instance, owner):
        print(‘这是我们自己定制的静态属性,r1.area实际是要执行r1.area()‘)
        if instance is None:
            return self
        return self.func(instance) #此时你应该明白,到底是谁在为你做自动传递self的事情

class Room:
    def __init__(self,name,width,length):
        self.name=name
        self.width=width
        self.length=length

    @Lazyproperty #area=Lazyproperty(area) 相当于定义了一个类属性,即描述符
    def area(self):
        return self.width * self.length

r1=Room(‘alex‘,1,1)
print(r1.area)      #将r1.area传参数写在Lazyproperty中的__get__里

 应用:自制property实现延迟计算功能

# -*- coding: utf-8 -*-
class Lazyproperty:
    def __init__(self,func):
        self.func=func
    def __get__(self, instance, owner):
        print(‘这是我们自己定制的静态属性,r1.area实际是要执行r1.area()‘)
        if instance is None:
            return self
        else:
            print(‘--->‘)
            value=self.func(instance)
            setattr(instance,self.func.__name__,value) #计算一次就缓存到实例的属性字典中
            return value
    # 如果加了set,将该非数据描述符变为数据描述符,优先级高于实列属性,缓存能力丧失
    # def __set__(self, instance, value):
    #     print(‘hahahahahah‘)

class Room:
    def __init__(self,name,width,length):
        self.name=name
        self.width=width
        self.length=length

    @Lazyproperty #area=Lazyproperty(area) 相当于‘定义了一个类属性,即描述符‘
    def area(self):
        return self.width * self.length

r1=Room(‘alex‘,1,1)
print(r1.area) #先从自己的属性字典找,没有再去类的中找,然后出发了area的__get__方法
print(r1.area) #先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算

property补充:一个静态属性property本质就是实现了get,set,delete三种方法

# -*- coding: utf-8 -*-
class Foo:
    @property
    def AAA(self):
        print(‘get的时候运行我啊‘)

    @AAA.setter
    def AAA(self,value):
        print(‘set的时候运行我啊‘)

    @AAA.deleter
    def AAA(self):
        print(‘delete的时候运行我啊‘)

#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA=‘aaa‘
del f1.AAA

应用(类型检测)

# -*- coding: utf-8 -*-
class People:
    def __init__(self,name):
        self.name=name #实例化就触发property

    @property
    def name(self):
        # return self.name #无限递归
        print(‘get------>‘)
        return self.DouNiWan

    @name.setter
    def name(self,value):
        print(‘set------>‘)
        if not isinstance(value,str):
            raise TypeError(‘必须是字符串类型‘)
        self.DouNiWan=value

    @name.deleter
    def name(self):
        print(‘delete------>‘)
        del self.DouNiWan

p1=People(‘alex‘) #self.name实际是存放到self.DouNiWan里
print(p1.name)

print(p1.__dict__)
p1.name=1

 元类

所有定义的类都是由type产生的。

# -*- coding: utf-8 -*-
class foo:
    pass
print(type(foo))

定义类的两种方法

# -*- coding: utf-8 -*-
class foo:
    pass
print(type(foo))
print(foo)

def __init__(self,name,age):
    self.name=name
    self.age=age

def test(self):
    print(‘=======>‘)
Foo=type(‘foo1‘,(object,),{‘x‘:1,‘__init__‘:__init__,‘test‘:test})
print(Foo)
print(Foo.__dict__)
foo_1=Foo(‘alex‘,22)
foo_1.test()

自定义元类(详情查看连接)