本文主要介绍Python高阶知识中的属性管理,这部分知识在常规Python编程中用的很少,但对于想深度了解Python甚至有志于自己编写实用框架的人,还是很有必要的,并且如果掌握了,对日常的代码学习等也会有一定好处。
本文结合笔者的经验,以及参考各种专业书籍和文章博客,抽丝剥茧,去掉可能导致混淆不清甚至错误的信息,归总而成,不再废话,直接上文。
属性管理机制主要是为控制对类属性的访问、更新、删除等的操作,借此可实现对属性访问行为的定制化控制,或者变相实现真正的私有属性或变量的需求。
Python随着版本更新和功能演变迭代,大体实现了3大类的属性管理机制,对应应用场景和抽象程度各有不同,以下会分别介绍。
这种机制主要借助于Python解释器中属性设置和访问对应魔法函数相关机制:
class A:
def __init__(self):
self.name='dennis'
def __getattribute__(self,key):
#注意,这里需要使用super调用对应方法,否则会循环调用,陷入死循环
return super().__getattribute__(key)
def __setattr__(self,key,value):
#这里可以使用以下两种方式进行属性值更新
self.__dict__[key]=value
super().__setattr__(key,value)
以下代码即演示,添加了对访问类或对象不存在的属性时自动调用的__getattr__魔法函数,在此可以添加自己的控制或者处理业务逻辑
class A:
def __init__(self):
self.name='dennis'
def __getattribute__(self,key):
#注意,这里需要使用super调用对应方法,否则会循环调用,陷入死循环
return super().__getattribute__(key)
def __setattr__(self,key,value):
#这里可以使用以下两种方式进行属性值更新
self.__dict__[key]=value
super().__setattr__(key,value)
def __getattr__(self,key):
raise AttributeError(f'error:访问的{key}不存在')
上面介绍的通过魔法函数进行属性管理,是对所有属性都进行了管理,本部分主要介绍对指定属性进行管理的机制,也即property内置方法,直接上代码
class A:
def __init__(self):
self.__name='dennis'
def setName(self,value):
self.__name=value
def getName(self):
return self.__name
def delName(self):
del self.delName
name=property(fget=getName,fset=setName,fdel=delName)
以上代码实现了对name属性的访问、更新、删除的管理,本质类似是一种委托机制,最终修改的是self.__name这个私有属性。
@property装饰器,是property方法的一种语法变体,最终作用相同,直接贴代码:
class A:
def __init__(self):
self.__name='dennis'
@property
def name(self):
return self.__name
@name.setter
def name(self,value):
self.__name=value
@name.deleter
def name(self):
del self.__name
描述符机制是相对来说抽象程度最深的属性管理机制,其可复用,可继承派生,本质来说,描述符是一种类,这种类内包含有__get__、__set__、__delete__方法的任意一个,而该类的实例会被作为拥有者(owner,即制定属性所属对象)的类属性,当拥有者访问对应属性时,会自动调用描述符类对应的方法。
以上描述比较抽象,具体上代码:
class StringField:
def __init__(self,string):
self.__string=string
def __get__(self,instance_obj,owner_class):
print('__get__')
return self.__string
def __set__(self,instance_obj,value):
print('__set__')
self.__string=value
def __delete__(self,instance_obj):
print('__delete__')
del self.__sting
class A:
name=StringField('dennis')
a=A()
a.name
a.name='tony'
del a
'''
会依次打印出
__get__
__set__
__delete__
'''
以上代码要点解释如下:
所以,了解甚至熟悉描述符,对更好的理解和使用流行框架也是大有益处的。
这个内置属性,可以控制某类实例对象(注意,不包含类属性,以及方法)可定义的属性名范围。相较于不使用__slots__,可显著提升属性访问速度,如果在设计类时,已明确有哪些实例属性,可采用该方式框死属性范围,避免误操作并提升代码执行效率。
class D:
__slots__=['name']
age=10
如上代码,D类的实力对象只能定义和使用name属性,如果定义其他属性,会引发AttributeError