目录python
描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议缓存
__get__():调用一个属性时,触发框架
__set__():为一个属性赋值时,触发函数
__delete__():采用del删除属性时,触发工具
定义一个描述符3d
class Foo: # 在python3中Foo是新式类,它实现了__get__(),__set__(),__delete__()中的一个三种方法的一个,这个类就被称做一个描述符 def __get__(self, instance, owner): pass def __set__(self, instance, value): pass def __delete__(self, instance): pass
class Foo: def __get__(self, instance, owner): print('触发get') def __set__(self, instance, value): print('触发set') def __delete__(self, instance): print('触发delete') f1 = Foo()
f1.name = 'nick' f1.name del f1.name
class Str: """描述符Str""" def __get__(self, instance, owner): print('Str调用') def __set__(self, instance, value): print('Str设置...') def __delete__(self, instance): print('Str删除...') class Int: """描述符Int""" def __get__(self, instance, owner): print('Int调用') def __set__(self, instance, value): print('Int设置...') def __delete__(self, instance): print('Int删除...') class People: name = Str() age = Int() def __init__(self, name, age): # name被Str类代理,age被Int类代理 self.name = name self.age = age # 何地?:定义成另一个类的类属性 # 什么时候?:且看下列演示 p1 = People('alex', 18)
Str设置... Int设置...
p1.name p1.name = 'nick' del p1.name
Str调用 Str设置... Str删除...
p1.age p1.age = 18 del p1.age
Int调用 Int设置... Int删除...
print(p1.__dict__) print(People.__dict__)
{} {'__module__': '__main__', 'name': <__main__.Str object at 0x107a86940>, 'age': <__main__.Int object at 0x107a863c8>, '__init__': <function People.__init__ at 0x107ba2ae8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
print(type(p1) == People) # type(obj)实际上是查看obj是由哪一个类实例化来的 print(type(p1).__dict__ == People.__dict__)
True True
class Foo: def __set__(self, instance, value): print('set') def __get__(self, instance, owner): print('get')
class Foo: def __get__(self, instance, owner): print('get')
描述符自己应该定义成新式类,被代理的类也应该是新式类代理
必须把描述符定义成这个类的类属性,不能为定义到构造函数中code
要严格遵循该优先级,优先级由高到底分别是对象
1.类属性blog
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
class Str: def __init__(self, name): self.name = name def __get__(self, instance, owner): print('get--->', instance, owner) return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->', instance, value) instance.__dict__[self.name] = value def __delete__(self, instance): print('delete--->', instance) instance.__dict__.pop(self.name) class People: name = Str('name') def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary p1 = People('nick', 18, 3231.3)
set---> <__main__.People object at 0x107a86198> nick
print(p1.__dict__)
{'name': 'nick', 'age': 18, 'salary': 3231.3}
print(p1.name)
get---> <__main__.People object at 0x107a86198> <class '__main__.People'> nick
print(p1.__dict__)
{'name': 'nick', 'age': 18, 'salary': 3231.3}
p1.name = 'nicklin' print(p1.__dict__)
set---> <__main__.People object at 0x107a86198> nicklin {'name': 'nicklin', 'age': 18, 'salary': 3231.3}
print(p1.__dict__)
{'name': 'nicklin', 'age': 18, 'salary': 3231.3}
del p1.name print(p1.__dict__)
delete---> <__main__.People object at 0x107a86198> {'age': 18, 'salary': 3231.3}
class Str: def __init__(self, name): self.name = name def __get__(self, instance, owner): print('get--->', instance, owner) return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->', instance, value) instance.__dict__[self.name] = value def __delete__(self, instance): print('delete--->', instance) instance.__dict__.pop(self.name) class People: name = Str('name') def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary # 疑问:若是我用类名去操做属性呢 try: People.name # 报错,错误的根源在于类去操做属性时,会把None传给instance except Exception as e: print(e)
get---> None <class '__main__.People'> 'NoneType' object has no attribute '__dict__'
class Str: def __init__(self, name): self.name = name 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) instance.__dict__[self.name] = value def __delete__(self, instance): print('delete--->', instance) instance.__dict__.pop(self.name) class People: name = Str('name') def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary print(People.name) # 完美,解决
get---> None <class '__main__.People'> <__main__.Str object at 0x107a86da0>
class Str: 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) class People: name = Str('name', str) # 新增类型限制str def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary try: p1 = People(123, 18, 3333.3) # 传入的name因不是字符串类型而抛出异常 except Exception as e: print(e)
set---> <__main__.People object at 0x1084cd940> 123 Expected <class 'str'>
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) class People: name = Typed('name', str) age = Typed('name', int) salary = Typed('name', float) def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary try: p1 = People(123, 18, 3333.3) except Exception as e: print(e)
set---> <__main__.People object at 0x1082c7908> 123 Expected <class 'str'>
try: p1 = People('nick', '18', 3333.3) except Exception as e: print(e)
set---> <__main__.People object at 0x1078dd438> nick set---> <__main__.People object at 0x1078dd438> 18 Expected <class 'int'>
p1 = People('nick', 18, 3333.3)
set---> <__main__.People object at 0x1081b3da0> nick set---> <__main__.People object at 0x1081b3da0> 18 set---> <__main__.People object at 0x1081b3da0> 3333.3
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 p1 = People('nick', 18, 3333.3)
类的装饰器开始运行啦------>
def typeassert(**kwargs): def decorate(cls): print('类的装饰器开始运行啦------>', kwargs) 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 p1 = People('nick', 18, 3333.3)
类的装饰器开始运行啦------> {'name': <class 'str'>, 'age': <class 'int'>, 'salary': <class 'float'>}
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('nick', 18, 3333.3)
类的装饰器开始运行啦------> {'name': <class 'str'>, 'age': <class 'int'>, 'salary': <class 'float'>} {'__module__': '__main__', '__init__': <function People.__init__ at 0x10797a400>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, 'name': <__main__.Typed object at 0x1080b2a58>, 'age': <__main__.Typed object at 0x1080b2ef0>, 'salary': <__main__.Typed object at 0x1080b2c18>} set---> <__main__.People object at 0x1080b22e8> nick set---> <__main__.People object at 0x1080b22e8> 18 set---> <__main__.People object at 0x1080b22e8> 3333.3
描述符是能够实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性
描述父是不少高级库和框架的重要工具之一,描述符一般是使用到装饰器或者元类的大型框架中的一个组件.
class Room: def __init__(self, name, width, length): self.name = name self.width = width self.length = length @property def area(self): return self.width * self.length r1 = Room('alex', 1, 1)
print(r1.area)
1
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实际是要执行r1.area() 1
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 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__方法
这是咱们本身定制的静态属性,r1.area实际是要执行r1.area() ---> 1
print(r1.area) # 先从本身的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
1
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: value = self.func(instance) instance.__dict__[self.func.__name__] = value return value # return self.func(instance) # 此时你应该明白,究竟是谁在为你作自动传递self的事情 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
print(Room.__dict__)
{'__module__': '__main__', '__init__': <function Room.__init__ at 0x107d53620>, 'area': <__main__.Lazyproperty object at 0x107ba3860>, '__dict__': <attribute '__dict__' of 'Room' objects>, '__weakref__': <attribute '__weakref__' of 'Room' objects>, '__doc__': None}
r1 = Room('alex', 1, 1) print(r1.area) print(r1.area) print(r1.area)
这是咱们本身定制的静态属性,r1.area实际是要执行r1.area() 1 这是咱们本身定制的静态属性,r1.area实际是要执行r1.area() 1 这是咱们本身定制的静态属性,r1.area实际是要执行r1.area() 1
print( r1.area ) #缓存功能失效,每次都去找描述符了,为什么,由于描述符实现了set方法,它由非数据描述符变成了数据描述符,数据描述符比实例属性有更高的优先级,于是全部的属性操做都去找描述符了
这是咱们本身定制的静态属性,r1.area实际是要执行r1.area() 1
class ClassMethod: def __init__(self, func): self.func = func def __get__( self, instance, owner): #类来调用,instance为None,owner为类自己,实例来调用,instance为实例,owner为类自己, def feedback(): print('在这里能够加功能啊...') return self.func(owner) return feedback class People: name = 'nick' @ClassMethod # say_hi=ClassMethod(say_hi) def say_hi(cls): print('你好啊,帅哥 %s' % cls.name) People.say_hi() p1 = People()
在这里能够加功能啊... 你好啊,帅哥 nick
p1.say_hi()
在这里能够加功能啊... 你好啊,帅哥 nick
class ClassMethod: def __init__(self, func): self.func = func def __get__(self, instance, owner ): # 类来调用,instance为None,owner为类自己,实例来调用,instance为实例,owner为类自己, def feedback(*args, **kwargs): print('在这里能够加功能啊...') return self.func(owner, *args, **kwargs) return feedback class People: name = 'nick' @ClassMethod # say_hi=ClassMethod(say_hi) def say_hi(cls, msg): print('你好啊,帅哥 %s %s' % (cls.name, msg)) People.say_hi('你是那偷心的贼') p1 = People()
在这里能够加功能啊... 你好啊,帅哥 nick 你是那偷心的贼
p1.say_hi('你是那偷心的贼')
在这里能够加功能啊... 你好啊,帅哥 nick 你是那偷心的贼
class StaticMethod: def __init__(self, func): self.func = func def __get__( self, instance, owner): # 类来调用,instance为None,owner为类自己,实例来调用,instance为实例,owner为类自己 def feedback(*args, **kwargs): print('在这里能够加功能啊...') return self.func(*args, **kwargs) return feedback class People: @StaticMethod # say_hi = StaticMethod(say_hi) def say_hi(x, y, z): print('------>', x, y, z) People.say_hi(1, 2, 3) p1 = People()
在这里能够加功能啊... ------> 1 2 3
p1.say_hi(4, 5, 6)
在这里能够加功能啊... ------> 4 5 6