我们已经准备好了,你呢?

2026我们与您携手共赢,为您的企业形象保驾护航!

一文解密中和的用法与区别

更新于: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()将引发错误,原因是字符串不具备被调用的功能。

上述内容阐述了两者之间的差异及其应用方法,在工作中不妨尝试运用它们。然而,坦白讲,前者在使用上较为普遍,而后者则相对较少,至少在我这里,使用频率并不高。

这篇文章对中和的运用及其差异进行了详细解读,现已全部介绍完毕。如需了解更多相关信息,请查阅脚本之家过往发布的文章,或继续阅读下方的相关内容。在此,我们衷心希望各位读者今后能继续支持脚本之家!

二维码
扫一扫在手机端查看

本文链接:https://by928.com/9563.html     转载请注明出处和本文链接!请遵守 《网站协议》
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。

项目经理在线

我们已经准备好了,你呢?

2020我们与您携手共赢,为您的企业形象保驾护航!

在线客服
联系方式

热线电话

13761152229

上班时间

周一到周五

公司电话

二维码
微信
线