__setattr__递归错误

1. 设置属性发送了什么?

class A(object):
    def __init__(self):
        self.a = 1


obj = A()
print(obj.a)  # 1

obj.b = 2
print(obj.b)  # 2

'''
    self.属性=值 会触发 __setattr__方法
    自定义类 A没有定义这个方法, 会调用父类的object的__setattr__的方法
	
	class object:
	    ...
	    
        def __setattr__(self, *args, **kwargs): # real signature unknown 真实签名未知
        """ Implement setattr(self, name, value). """
        pass 
        _________________C语言写的看不到源码_____________________
'''

2. 自定义setattr方法递归错误

一般情况下, 创建对象, 不会自己写__setattr__方法. 下面为演示代码不要纠结...
class A(object):
    # 自定义__setattr__
    def __setattr__(self, key, value):
        # .后面的属性被作为参数传递给key, 赋值符号后面的值被作为参数传递给value
        self.key = value


obj = A()
obj.a = 1

print(obj.a)

运行上面这个程序会提示报错
RecursionError: maximum recursion depth exceeded 递归错误:超过最大递归深度
每次在遇到 self.属性= 时候会触发setattr, 
在setattr中有 self.属性= 再次触发setattr, 这就造成了无限循环, 最终报错.

2022-10-22_00867

3. 解决问题

在setattr中有 self.属性= 会自己触发自己, 只要避免自己调用自己就可以解决问题.
在setattr中不要出现 self.属性=, 又能设置值即可.
3.1 方式1 父类中更新子类的值
使用object的setattr方法, 在父类中更新子类的值.
class A(object):
    # 自定义__setattr__
    def __setattr__(self, key, value):
        # 使用object类的setattr方法, 将所有参数传递
        object.__setattr__(self, key, value)


obj = A()
obj.a = 1

print(obj.a)  # 1
3.2 方法2 以字典形式修改值
class A(object):
    # 自定义__setattr__
    def __setattr__(self, key, value):
        """
        对象.__dict__可以将对象的所有属性以字典的形式展示,
        支持self.__dict__[key] = value 添加修改值
        """
        self.__dict__[key] = value


obj = A()
obj.a = 1

print(obj.a)  # 1

obj.__dict__['b'] = 2
print(obj.__dict__)  # {'a': 1, 'b': 2}

4. 字典使用.属性

Python中的字典, 使没有办法通过字典.key取到value值的.
Python中一切都是对象, 字典也是对象, 
之所有字典.key会报错则是没有在创建字典对象的类中写__setattr__与__getattr__方法.
class MyDict(dict):
    # 点拦截设置值
    def __setattr__(self, key, value):
        # dict继承object类, 可以直接用
        object.__setattr__(self, key, value)

    # 点拦截获取值
    def __getattr__(self, item):
        return self.item


dic = MyDict()
print(dic)

dic['name'] = 'kid'
dic.age = 18

print(dic)
print(dic.age)

终端显示:
{}
{'name': 'kid'}
18
_______________________________________
现在字典是可以使用点, 但是值不在同一空间中.
字典使用[]会触发dict.__setitem__方法, 那么再__setattr__使用dict.__setitem__即可.
class MyDict(dict):

    # 点拦截设置值
    def __setattr__(self, key, value):
        # [] 拦截 触发__setitem__, 为字典中添加键值对
        dict.__setitem__(self, key, value)

    # 点拦截获取值
    def __getattr__(self, item):
        # self是字典对象, 使用字典的get方法获取字典的值
        return self.get(item)


dic = MyDict()
print(dic)

dic['name'] = 'kid'
dic.age = 18

print(dic)
print(dic.name, dic.age)

终端显示:
{}
{'name': 'kid', 'age': 18}
kid 18
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值