首页 > 编程语言 >python类的实现中有关__setattr__原理问题

python类的实现中有关__setattr__原理问题

时间:2024-02-15 21:22:40浏览次数:33  
标签:__ obj name setattr python self ._ attributes

python类的实现中有关__settar__原理问题

具体解决思路

问题代码段:

    class CustomAttributes:
        def __init__(self):
            self._attributes = {}

        def __setattr__(self, name, value):
            # 允许设置名为 '_attributes' 的属性,这是实现所必需的  
            if name == '_attributes':
                super().__setattr__(name, value)
                # 对于其他属性,添加它们到 _attributes 字典中
            else:
                self._attributes[name] = value

        def __getattr__(self, name):
            # 尝试从 _attributes 字典中获取属性  
            if name in self._attributes:
                return self._attributes[name]
                # 如果属性不存在,则调用默认的 __getattr__ 实现
            else:
                raise AttributeError(f"'CustomAttributes' object has no attribute '{name}'")

            # 创建一个 CustomAttributes 实例


    obj = CustomAttributes()

    # 设置属性  
    obj.name = 'Alice'
    obj.age = 35

    # 访问属性  
    print(obj.name)  # 输出: Alice  
    print(obj.age)  # 输出: 35

在这段代码中,我发现特殊方法__setattr__中有段未知代码 super().__setattr__(name, value),我要对其功能进行一个测试。

  1. 在代码测试中加入_attributes的value。

    import CustomAttributes
    
    obj = CustomAttributes()
    
    # 设置属性  
    obj.name = 'Alice'
    obj.age = 35
    obj._attrubites = 10
    
    # 访问属性  
    print(obj.name)  
    print(obj.age)
    print(obj._attributes)
    '''
    输出:
    Traceback (most recent call last):
        File "C:\Users\GOD\Desktop\301.py", line 32, in <module>
            print(obj.name)
                ^^^^^^^^
        File "C:\Users\GOD\Desktop\301.py", line 15, in __getattr__
            if name in self._attributes:
            ^^^^^^^^^^^^^^^^^^^^^^^^
        TypeError: argument of type 'int' is not iterable
    '''
    
    import CustomAttributes
    
    obj = CustomAttributes()
    
    # 设置属性  
    obj.name = 'Alice'
    obj.age = 35
    obj._attributes = 10
    
    # 访问属性  
    print(obj._attributes)  # 输出:10
    
    

    由此得知,super().__setattr__(name, value)这段代码的功能是使 _attributes的key可以覆盖原属性dict。

  2. 删掉这段代码,测试其是否为重要组成部分。

    class CustomAttributes:
        def __init__(self):
            self._attributes = {}
    
        def __setattr__(self, name, value):
            self._attributes[name] = value
    
        def __getattr__(self, name):
            # 尝试从 _attributes 字典中获取属性
            if name in self._attributes:
                return self._attributes[name]
                # 如果属性不存在,则调用默认的 __getattr__ 实现
            else:
                raise AttributeError(f"'CustomAttributes' object has no attribute '{name}'")
    
            # 创建一个 CustomAttributes 实例
    
    
    obj = CustomAttributes()
    
    '''
    输出:
    Traceback (most recent call last):
        File "C:\Users\GOD\Desktop\301.py", line 19, in <module>
            obj = CustomAttributes()
                ^^^^^^^^^^^^^^^^^^
        File "C:\Users\GOD\Desktop\301.py", line 3, in __init__
            self._attributes = {}
            ^^^^^^^^^^^^^^^^
        File "C:\Users\GOD\Desktop\301.py", line 6, in __setattr__
            self._attributes[name] = value
            ^^^^^^^^^^^^^^^^
        File "C:\Users\GOD\Desktop\301.py", line 10, in __getattr__
            if name in self._attributes:
                    ^^^^^^^^^^^^^^^^
        File "C:\Users\GOD\Desktop\301.py", line 10, in __getattr__
            if name in self._attributes:
                    ^^^^^^^^^^^^^^^^
        File "C:\Users\GOD\Desktop\301.py", line 10, in __getattr__
            if name in self._attributes:
                    ^^^^^^^^^^^^^^^^
        [Previous line repeated 743 more times]
    RecursionError: maximum recursion depth exceeded
    '''
    

    由此得知,去除掉这段代码会导致触发无限递归,
    __init__ 方法在创建 CustomAttributes 实例时被调用时,它尝试设置 _attributes 字典。这触发了 __setattr__ 方法的调用。
    __setattr__ 方法内部,当尝试访问 self._attributes 时,由于 _attributes 字典尚未完全初始化,Python 会调用 __getattr__ 方法来获取该属性。
    然后,__getattr__ 方法又尝试检查 name 是否在 self._attributes 中,这再次触发了 __getattr__ 的调用,从而形成了无限递归。

总结

  1. 由两个实验得之:
    uper().__setattr__(name, value)允许你绕过当前类中的 __setattr__方法,并直接调用其父类的 __setattr__方法。
  2. __init__方法创建实例时被调用时,会调用 __setattr__方法去设置实例的属性,当在 __setattr__方法内部尝试访问,由于 _attributes 字典尚未完全初始化,Python 会调用 __getattr__ 方法来获取该属性,从而造成递归循环。

标签:__,obj,name,setattr,python,self,._,attributes
From: https://www.cnblogs.com/LPF05/p/18016615/lpf-__setattr__-problem1

相关文章

  • 《SagDRE: Sequence-Aware Graph-Based Document-Level Relation Extraction with Ada
    代码原文地址关键参考文献:Document-LevelRelationExtractionwithAdaptiveThresholdingand LocalizedContextPooling摘要关系抽取(RE)是许多自然语言处理应用的重要任务,它的目标是从文档中抽取出实体之间的关系。文档级RE任务面临着许多挑战,因为它不仅需要跨句子......
  • 每日总结
    Scala访问修饰符Scala访问修饰符基本和Java的一样,分别有:private,protected,public。如果没有指定访问修饰符,默认情况下,Scala对象的访问级别都是public。Scala中的private限定符,比Java更严格,在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。私有(Private)成员......
  • Go - map
       ......
  • 单位根反演
    单位根反演通常用于求\(\sum\limits_{i=0}^n[x\midi]f_i\)。形式\[[n\midk]=\frac{1}{n}\sum\limits_{i=0}^{n-1}\omega_n^{ik}\]其中\(\omega_n\)是\(n\)次单位根,模意义下可以被原根替换。证明当\(n\midk\)时,\(\omega_n^{ki}=1\)。所以右边等于\(\frac{1}{n}......
  • 30天自制操作系统
    01_daysCPU其实只算是个集成电路板,它只能忠实地执行电信号给它的指令,输出相应的电信号。也就是说,其实CPU只是个乖乖执行命令的笨蛋。人们发现把二进制的01与电信号的开关对应起来,CPU就从一个处理电信号的机器摇身一变为一个神奇的二进制数计算机。给文字进行编码,就把文字也转换......
  • bug-missing GOSUMDB
     问题描述:D:\gopj>gomodtidygo:findingmoduleforpackagego.uber.org/zapgo:findingmoduleforpackagegithub.com/valyala/fasthttpgo:downloadinggo.uber.org/zapv1.26.0go:downloadinggithub.com/valyala/fasthttpv1.52.0go:githun.com/bigwh......
  • 写给2024(2.10)
    今天之后就进入了新的一年。去年的上半年算是糊糊涂涂过去的,六月份军训结束状态好了一些,至少心里有想去的地方了。下半年转专业到了计算机系,刚开学那段时间每天背着游戏本和一千多页的java编程思想,四处找空教室自习,偶尔被社团办活动的请出去。因为笔记本老没电,开始寻找插......
  • 预算紧缩下创新创业者应采取哪3个策略来保持创新?
    在今天越来越饱和的消费市场中,品牌零售通过复杂、过度的的促销、折扣、优惠券和忠诚度奖励来吸引消费者,但这种做法可能削弱消费者的忠诚度,损害品牌声誉,并抑制新的收入机会。相反,零售商应采取更简化、以客户为中心的方法。通过更准确地了解促销活动的有效性,帮助更明智地决策适......
  • vscode中无法识别go命令
    现象描述:装好go在cmd下面输入goversion能正常显示但在vscode控制台中无法显示原因:vscode未识别到go命令解决方案:手动为vscode添加go的path路径 打开VSCode设置(JSON):你可以通过按下Ctrl+Shift+P打开命令面板,然后输入OpenSettings(JSON)并选择它来直......
  • 数组成鸡
    数组成鸡题目描述小鸡有一个由整数组成的数组,小鸡可以对这个数组进行任意次(可以不进行)全数组每个数加一或全数组每个数减一的操作。现在,小鸡想让你回答$Q$次询问,每次询问给出一个整数$M$,你需要回答任意次(可以不操作)操作后是否可以使得给定数组的乘积等于给出的整数$M$。输......