
我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈
入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈
虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈
PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈
Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈
优 质 资 源 下 载 :👉👉 资源下载合集 👈👈

__get__, __set__, __delete__)来拦截属性访问行为的对象__get__方法来获取属性值(p[age])__set__方法,则可以通过赋值操作修改属性的值(p[age] = 36)__delete__方法,则可以使用del语句删除属性(del p[age])class Person(object):
def __init__(self):
self.age = 18
a = int(input('请输入年龄:'))
p = Person()
print('你当前的年龄是:', p.age)
p.age = a
print('你当前的年龄是:', p.age)
# 输出
# 你当前的年龄是:18
# 请输入年龄:-100
# 你当前的年龄是: -100
# 这个示例中,age属性没有使用描述器,所以在外部我们可以随意修改,无法对属性的操作进行拦截控制
# 对于用户输入的年龄是否合格,只能在实例化对象之前进行判断,但是每次实例化对象的时候都要加这个判断,会出现很多冗余代码
class Person(object):
def __init__(self):
self.__age = 18
def get_age(self):
return self.__age
def set_age(self, value):
# 可以在这里对属性设置的值进行判断
if value < 0 or value > 180:
print('你输入的年龄太小或者太大了!')
else:
self.__age = value
def del_age(self):
del self.__age
age = property(get_age, set_age, del_age)
p = Person()
print(p.age)
p.age = -100
print(p.age)
# 输出
# 18
# 你输入的年龄太小或者太大了!
# 18


property(get_xxx, set_xxx, del_xxx)实例对象@property、@xxx.setter、@xxx.deleter装饰器__get__, __set__, __delete__类.属性的方式操作属性时,只会调用 __get__ 方法,不会调用 __set__ 和 __delete__ 方法property(get_xxx, set_xxx, del_xxx)实例对象class Person(object):
def __init__(self):
self.__age = 18
def get_age(self):
return self.__age
def set_age(self, value):
# 可以在这里对属性设置的值进行判断
if value < 0 or value > 180:
print('你输入的年龄太小或者太大了!')
else:
self.__age = value
def del_age(self):
del self.__age
age = property(get_age, set_age, del_age)
p = Person()
print(p.age) # 18
p.age = -100 # 你输入的年龄太小或者太大了!
print(p.age) # 18
@property、@xxx.setter、@xxx.deleter装饰器class Person(object):
def __init__(self):
self.__age = 18
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
if value < 0 or value > 100:
print('你输入的年龄太小或者太大了!')
else:
self.__age = value
@age.deleter
def age(self):
print('删除前可进行删除判断')
del self.__age
p = Person()
print(p.age) # 18
p.age = -100 # 你输入的年龄太小或者太大了!
print(p.age) # 18
class Age:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法')
def __delete__(self, instance):
print('__delete__方法')
class Person(object):
age = Age()
# p = Person()
#
# p.age # __get__方法
# p.age = 100 # __set__方法
# p.age # __get__方法
# del p.age # __delete__方法
Person.age # __get__方法
Person.age = 100 # 不会调用__set__方法
del Person.age # 不会调用__delete__方法
# Person.age
# 通过`类.属性`的方式操作属性时,只会调用 `__get__` 方法,不会调用 `__set__` 和 `__delete__` 方法
__dict__字典中查找属性,如果存在则返回。__dict__字典中查找属性,如果存在则返回。__dict__字典中查找属性,如果存在则返回。__getattr__方法,就会调用这个方法__get__方法__get__方法被优先调用的原因
__getattnibute__方法来实现__getattnibute__方法内部实现过程
__get__方法,如果有就会直接调用__get__方法,则按照上面的查找机制进行查找__getattnibute__方法,则不会执行描述器的__get__方法了__get__和__set__方法的描述器__get__方法的描述器class Age:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法')
class Person(object):
age = Age()
p = Person()
p.age # __get__方法
p.age = 10 # __set__方法
class Age:
def __get__(self, instance, owner):
print('__get__方法')
class Person(object):
age = Age()
p = Person()
p.age # __get__方法
p.age = 10
class Age:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法')
class Person(object):
age = Age()
def __init__(self):
self.age = 10
p = Person()
p.age = 100
p.age
print(p.__dict__)
# 输出结果
# __set__方法 # p = Person() 实例化对象时会自动执行__init__初始化方法,执行 self.age = 10 调用了描述器里面的__set__方法
# __set__方法 # 执行 p.age = 100 时,又自动调用描述器里面的__set__方法
# __get__方法 # 执行 p.age 时,自动调用描述器里面的 __get__方法
# {} # 执行 self.age = 10 时,调用了描述器里重写的 __set__ 方法,仅仅只是打印了__set__字符,没有做其他操作,所以实例中并没有添加 age 属性
# 整个过程都是优先执行了资料描述器里面的__get__方法和__set__方法,并没有执行实例属性
class Person(object):
age = Age()
def __init__(self):
self.age = 10
p = Person()
p.age = 100
p.age
print(p.__dict__)
# 输出结果
{'age': 100} # p = Person() 实例化对象时会自动执行__init__初始化方法,执行了 self.age = 10 ,将age属性直接添加到了实例对象的__dict__字典中,
# 并没有调用描述器内部的__set__方法
# 整个执行过程中优先执行了实例属性,并没有执行非资料描述器
上面我们讲的这些案例中,仅仅只是实现了描述器中的__get__、__set__、__delete__方法,但是并没有真正实现值的存储,那么我们来看一下如何实现值的传递和存储
描述器示例
class Age(object):
"""描述器"""
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass
class Person(object):
age = Age()
def __init__(self):
self.age = 10
p = Person()
p.age = 100
上面的Age描述器中实现了__get__、__set__、__delete__三个方法,在这三个方法中有四个参数,我们来看一下这四个参数分别代表什么
# 描述器中值的存储
class Age(object):
"""描述器"""
def __get__(self, instance, owner):
print('self:', self)
print('instance:', instance)
print('owner:', owner)
def __set__(self, instance, value):
print('value:', value)
def __delete__(self, instance):
pass
class Person(object):
age = Age()
p = Person()
p.age
p.age = 199
# 输出结果
# self: <__main__.Age object at 0x000002A15828DFD0>
# instance: <__main__.Person object at 0x000002A15828DFA0>
# owner:
# value: 199

从输出结果可以看出来四个参数分别代表:
self: # 描述器Age类的实例化对象
instance: # Person类的实例化对象
owner: # Person类
value: # Person类实例化对象的属性值发生变化时的值

上面的示例可能还有点抽象,那么看下面这个示例
class Age(object):
"""描述器"""
a = 'Age类属性'
def __init__(self):
self.a = 'Age实例属性'
def __get__(self, instance, owner):
print('self:', self.a)
print('instance:', instance.a)
print('owner:', owner.a)
def __set__(self, instance, value):
print('value:', value)
def __delete__(self, instance):
pass
class Person(object):
age = Age()
a = 'Person类属性'
def __init__(self):
self.a = 'Person实例属性'
p = Person()
p.age
p.age = 199
# 输出结果
# self: Age实例属性
# instance: Person实例属性
# owner: Person类属性
# value: 199
def fashuoshuo()
print('发说说操作')
fashuoshuo()
def check(func):
def inner():
print('进行登录验证...')
func()
return inner
@check
def fashuoshuo():
print('发说说操作')
fashuoshuo()
def check(func):
def inner():
print('进行登录验证...')
func()
return inner
# @check
def fashuoshuo():
print('发说说操作')
fashuoshuo = check(fashuoshuo) # @check语法糖原理
# fashuoshuo这个变量接收到的是check这个方法的返回值:inner函数体
fashuoshuo()
# 此时这里执行的fashuoshuo(),实际上是执行的inner()
我们通过上面的函数装饰器可以看到@check这种语法糖模式,实际上就是执行了fashuoshuo = check(fashuoshuo)
那么我们现在通过反推的方式来理解类实现装饰器
我们先将前面的def check函数替换成class check类
class check:
pass
# @check
def fashuoshuo():
print('发说说操作')
# @check语法糖的执行原理
fashuoshuo = check(fashuoshuo)
# 这里实际上是实例化check类对象,会自动执行类内部的__init__方法
fashuoshuo()
在这个案例中fashuoshuo = check(fashuoshuo)这一句实际上是实例化check类的实例对象
在实例化示例对象的时候,就会默认调用类中的__init__方法,此时,我们还不知道在这个方法中执行什么,所有先不实现任何操作,用占位关键字占位
class check:
def __init__(self, func):
pass
# @check
def fashuoshuo():
print('发说说操作')
# @check语法糖的执行原理
fashuoshuo = check(fashuoshuo)
# 这里实际上是实例化check类对象,会自动执行类内部的__init__方法
fashuoshuo()
看样子,这样就搞定了…
But…

报错了!报错在第13行! fashuoshuo()… why???
…
哦!哦!哦!
fashuoshuo()这里的fashuoshuo已经不是一个函数了,这里是一个实例对象
实例对象默认是不允许通过加()调用执行的,要想通过加()调用执行,必须在类内部实现__call__方法
class check:
def __init__(self, func):
pass
def __call__(self, *args, **kwargs):
pass
# @check
def fashuoshuo():
print('发说说操作')
# @check语法糖的执行原理
fashuoshuo = check(fashuoshuo)
# 这里实际上是实例化check类对象,会自动执行类内部的__init__方法
fashuoshuo()
哦豁,没有报错,运行成功了!那么接下来我们就是要实现具体的功能了
那么,我们最终要执行的是def fashuoshuo()这个函数体,即在__call__这个方法中执行这个函数体
但是,在__call__这个方法中怎么拿到这个函数体呢?
我们在实例化check类的实例对象的时候,把fashuoshuo()这个函数体作为参数传入了进去
那么在__init__方法中就可以接收到这个函数体,我们把这个函数体保存在实例属性中
__call__方法再通过实例属性就可以执行这个函数体了
同样的,最后把要增加的操作执行在调用这个函数体之前就行了
class check:
def __init__(self, func):
self.f = func
def __call__(self, *args, **kwargs):
print('登录验证操作......')
self.f()
# @check
def fashuoshuo():
print('发说说操作')
# @check语法糖的执行原理
fashuoshuo = check(fashuoshuo)
# 这里实际上是实例化check类对象,会自动执行类内部的__init__方法
fashuoshuo()
最后用语法糖的模式优化一下
class check:
def __init__(self, func):
self.f = func
def __call__(self, *args, **kwargs):
print('登录验证操作......')
self.f()
@check
def fashuoshuo():
print('发说说操作')
fashuoshuo()
__init__方法中保存要装饰函数的函数体__call__方法中执行__init__方法中保存的函数,并且在执行之前进行其他新增的操作