一文解密中和的用法与区别
更新于:2023年1月13日14点52分28秒,撰文者为古明地觉。
本文详细阐述了中和的运用及其差异,其中借助若干简明实例进行了阐释,有需求者不妨查阅参考。
在尝试访问实例对象的一个不存在属性时,必然会出现错误,并且会引发异常。
class A: pass a = A() a.xxx """ 尝试访问对象'A'时,出现了错误信息,提示该对象不具备名为'xxx'的属性。 """
若我们期望在缺失特定属性的情况下,系统不抛出错误,而是直接返回预设的值,那么应该如何操作呢?在这种情况下,我们需要创建一个方法,该方法会在实例对象尝试访问不存在的属性时自动被调用执行。
class Girl:
def __init__(self):
self.name = "古明地觉"
self.age = 17
def get_info(self):
返回信息如下:姓名为{self.name},年龄为{self.age}。
在实例中调用未定义的属性时,此方法会被自动调用,并接收一个参数,即未找到的属性名称。
返回信息:你已查阅了{item}这一属性详情。
girl = Girl()
输出女孩的名字,以及她的年龄——古明地觉,十七岁。
print(girl.get_info) #
输出女孩的详细信息:姓名为古明地觉,年龄为十七岁。
输出:girl的xxx属性值 #你已经查看了xxx属性
输出girl对象的yyy属性值#你已查询yyy属性
输出girl对象的zzz属性值#你对zzz属性进行了查询
因此操作极其简便,当实例对象试图访问一个不存在的属性时,系统会自动调用特定方法。反之,若该属性确实存在,系统将直接返回其对应的值,而不会执行上述方法。
def __getattr__(name):
在模块`__name__`中并未发现标识符`{name}`。
name = "古明地觉"
age = 17
相信你明白它是干什么的了,我们来导入它:
导入工具模块中的name、age以及xxx和yyy等组件。 print(name, age) # 古明地觉 17 print(xxx) # tools 中不存在 xxx print(yyy) # tools 中不存在 yyy import tools 执行代码时发现,在tools模块中并未定义zzz这一变量。
在访问 tools.py 文件中的属性时,若该属性不存在,程序会继续执行,这个过程相对比较直观,操作并不复杂。
被称为属性拦截器,它比 要霸道的多,这两者的区别如下:
我们举个例子:
class Girl: def __init__(self): self.name = "古明地觉" self.age = 17 定义一个名为`__getattribute__`的方法,该方法接收两个参数:`self`和`item`。 执行操作:返回信息,内容为“读取属性值:”,后跟项目名称。 girl = Girl() 输出女孩的姓名属性,即girl.name。 print(girl.age) # 获取属性: age print(girl.xxx) # 获取属性: xxx # 即便你想通过属性字典获取也是没有用的 无论对象的何种特性,都会触发__getattribute__方法的调用。 输出女孩的属性信息:使用`__dict__`方法
在使用此方法时务必保持警惕,否则极易陷入无休止的循环之中。
class Girl: def __init__(self): self.name = "古明地觉" self.age = 17 def __getattribute__(self, item): 返回self对象中名为item的属性的值。 girl = Girl() print(girl.name) # 显然上面的代码会陷入无限递归 由于girl的name属性会触发__getattribute__方法。 因此,它将再次触发__getattribute__方法,进而导致无限循环调用。 # 可能有人说,那我换一种方式 答案并非有效,原因在于self.__dict__依旧在检索属性。 一旦属性被访问,便会激活__getattribute__方法,仍旧可能陷入无休止的递归循环。
所以 非常霸道,那么我们如何使用它呢?答案是通过父类。
class Girl:
def __init__(self):
self.name = "古明地觉"
self.age = 17
def __getattribute__(self, item):
执行返回操作,调用父类的__getattribute__方法,获取指定项的属性值。
girl = Girl()
print(girl.name)
print(girl.age)
try:
girl.xxx
except AttributeError:
print("属性 xxx 不存在")
"""
古明地觉
17
属性 xxx 不存在
"""
在调用父类的方法时,若该属性已被设定,系统将直接提供其值;若实例中缺少该属性,系统将检查是否已设定了相应的处理逻辑,若已设定,则执行该逻辑;若未设定,则会引发异常。将这两种处理方式融合,以下是一个示例:
class Girl:
def __init__(self):
self.name = "古明地觉"
self.age = 17
def __getattr__(self, item):
执行打印操作,输出"__getattr__"函数与"item"参数。
return f"获取属性 {item}"
def __getattribute__(self, item):
输出:`__getattribute__`函数,对应于项目`item`。
return super().__getattribute__(item)
girl = Girl()
无论属性是否设定,均需执行__getattribute__方法。
接着,我们再次在内部调用了父类的特殊方法,即`__getattribute__`。
检测属性是否具备,若存在,即刻提取相应数值,并予以返回。
print(girl.name)
"""
__getattribute__ name
古明地觉
"""
#年龄属性遵循同样的原则,与姓名属性相同,它们均存在于系统中。
print(girl.age)
"""
__getattribute__ age
17
"""
继续执行__getattribute__方法,紧随其后的是对父类中__getattribute__方法的调用。
若某属性xxx未被发现,系统将启动__getattr__机制。
print(girl.xxx)
"""
__getattribute__ xxx
__getattr__ xxx
获取属性 xxx
"""
如此一来,疑问便产生了,这究竟有何实际效用?该技术被称作属性拦截器,显而易见,它能够实现对属性访问权限的有效管控。
class Girl:
def __init__(self):
self.name = "古明地觉"
self.age = 17
def __getattr__(self, item):
若属性{item}未被发现,将返回信息:“该属性不存在。”
def __getattribute__(self, item):
if item == "age":
她的年龄不宜公开,若有人询问,只需回答尚未满18周岁。
return super().__getattribute__(item)
girl = Girl()
若存在name属性,则在__getattribute__方法中直接予以返回。
print(girl.name)
"""
古明地觉
"""
同样,在__getattribute__方法中,它也是直接进行返回操作。
# 只不过它相当于被拦截了
print(girl.age)
"""
女人芳龄不可泄露,别问,问就是还不到 18 岁
"""
在父类执行__getattribute__方法的过程中,若发现xxx属性并未定义。
因此,将启动__getattr__方法的运行(若该属性未事先设定,则会引发AttributeError异常)。
print(girl.xxx)
"""
属性 xxx 不存在
"""
因此,它相当于一个属性拦截器,无论尝试访问何种属性,都必须先通过它。若你发现某些属性不希望外界访问,可以简单地进行拦截,例如在上述代码中,对 age 属性的处理方式。
接下来,针对那些允许外部访问的特性,我们必须借助父类的方法来获取信息(若自行尝试获取,可能会陷入无限循环),同时,当尝试访问不存在的属性时,该方法也会自动执行处理。
当然啦,除了属性,方法也是一样的。
class Girl:
def __init__(self):
self.name = "古明地觉"
self.age = 17
def get_info(self):
return f"name: {self.name}, age: {self.age}"
def __getattribute__(self, item):
若项目等于“获取信息”:
return "此方法禁止获取"
return super().__getattribute__(item)
girl = Girl()
print(girl.get_info)
"""
此方法禁止获取
"""
在默认状态下,调用girl对象中的get_info方法。
# 然后再加上小括号就会执行该方法
然而,我们在__getattribute__方法中对它进行了拦截,并给出了一个字符串作为响应。
因此,此刻调用girl.get_info()将引发错误,原因是字符串不具备被调用的功能。
上述内容阐述了两者之间的差异及其应用方法,在工作中不妨尝试运用它们。然而,坦白讲,前者在使用上较为普遍,而后者则相对较少,至少在我这里,使用频率并不高。
这篇文章对中和的运用及其差异进行了详细解读,现已全部介绍完毕。如需了解更多相关信息,请查阅脚本之家过往发布的文章,或继续阅读下方的相关内容。在此,我们衷心希望各位读者今后能继续支持脚本之家!
扫一扫在手机端查看
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。


客服1