鱼C论坛

 找回密码
 立即注册
查看: 1371|回复: 12

[已解决]setattr问题

[复制链接]
发表于 2020-8-21 17:46:56 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
关于属性访问
class Rectangle:
    def __init__(self,width=0,height=0):

        self.width=width
        self.height=height

    def __setattr__(self,name,value):
        if name=='square':
            self.width=value
            self.height=value
        else:
           super().__setattr__(name,value)#self.name=value会导致无限递归

    def getArea(self):
        return self.width*self.height
            

关于正方形的问题 小甲鱼说在init调用时触发了__setattr__的方法然后执行了else的语句
self.width=value 这里的value 是width的值吗 执行到这里不就已经可以结束了吗
为什么会陷入死循环呢??看解释说是又再次触发了setattr这个方法 怎么看出来的 没懂

还有就是基类的__setattr__方法是什么内容呢好像之前没有提到过诶
最佳答案
2020-8-21 17:59:04
本帖最后由 Twilight6 于 2020-8-21 18:03 编辑


为什么会陷入死循环呢?


因为你不管执行 else 还是 if 代码块都有赋值操作,那么就会无限调用自身的 __setattr__ 方法

就好如你赋值调用了 __setattr__ , 结果进入 __setattr__ 方法后还是赋值操作,此时又调用自身,然后又是赋值操作又调用自身.....就永远没有出口了



去掉 else 里面的赋值操作,为什么不会陷入死循环呢?


首先 __init__ 方法里面有两个赋值操作:
self.width=width
self.height=height


此时假设你 实例化一个对象 r = Rectangle(5,100) 那么 __init__ 方法会自动执行:
self.width = 5
self.height = 100
这两个赋值操作会调用直接的 __setattr__ ;先来看第一个 self.width=5  因为这里进行了赋值操作,所以调用了自己的 __setattr__ 方法

在 __setattr__ 方法中 name参数指的就是被赋值的变量名,简单说就是等号左边的,而这里就是指 width ,而 value 是等号右边的 就是你传入的 5

也就是你赋值  self.width=5 时候  name = 'width'  而 value = 5

__setattr__ 方法中首先进行判断变量名 是否为 square ,这里很显然 name = 'width' 不等于 'square' 所以执行 else

else 是用 super 调用基类的 __setattr__方法 来给 width 赋值为 'square' ,而不是调用自己的 所以不会调用自己的 __setattr__方法

同理 self.height=height 也是一样的 , 所以这样就不会导致 无限递归调用 __setattr__方法 的情况发生了,因为赋值操作到最后都是执行 父类的 __setattr__ 方法,而不是自己类的 __setattr__ 方法


基类的__setattr__方法是什么内容呢?


在对一个属性设置值的时候,就会自动调到这个函数,每个设置值的方式都会进入这个方法,然后给对应变量设置对应的值。

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-8-21 17:59:04 | 显示全部楼层    本楼为最佳答案   
本帖最后由 Twilight6 于 2020-8-21 18:03 编辑


为什么会陷入死循环呢?


因为你不管执行 else 还是 if 代码块都有赋值操作,那么就会无限调用自身的 __setattr__ 方法

就好如你赋值调用了 __setattr__ , 结果进入 __setattr__ 方法后还是赋值操作,此时又调用自身,然后又是赋值操作又调用自身.....就永远没有出口了



去掉 else 里面的赋值操作,为什么不会陷入死循环呢?


首先 __init__ 方法里面有两个赋值操作:
self.width=width
self.height=height


此时假设你 实例化一个对象 r = Rectangle(5,100) 那么 __init__ 方法会自动执行:
self.width = 5
self.height = 100
这两个赋值操作会调用直接的 __setattr__ ;先来看第一个 self.width=5  因为这里进行了赋值操作,所以调用了自己的 __setattr__ 方法

在 __setattr__ 方法中 name参数指的就是被赋值的变量名,简单说就是等号左边的,而这里就是指 width ,而 value 是等号右边的 就是你传入的 5

也就是你赋值  self.width=5 时候  name = 'width'  而 value = 5

__setattr__ 方法中首先进行判断变量名 是否为 square ,这里很显然 name = 'width' 不等于 'square' 所以执行 else

else 是用 super 调用基类的 __setattr__方法 来给 width 赋值为 'square' ,而不是调用自己的 所以不会调用自己的 __setattr__方法

同理 self.height=height 也是一样的 , 所以这样就不会导致 无限递归调用 __setattr__方法 的情况发生了,因为赋值操作到最后都是执行 父类的 __setattr__ 方法,而不是自己类的 __setattr__ 方法


基类的__setattr__方法是什么内容呢?


在对一个属性设置值的时候,就会自动调到这个函数,每个设置值的方式都会进入这个方法,然后给对应变量设置对应的值。

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2020-8-21 18:42:35 | 显示全部楼层
Twilight6 发表于 2020-8-21 17:59
因为你不管执行 else 还是 if 代码块都有赋值操作,那么就会无限调用自身的 __setattr__ 方法

就 ...

else 是用 super 调用基类的 __setattr__方法 来给 width 赋值为 'square' ,
这句话是啥意思没懂???当我没有令   实例对象.square=value 的时候不是跟else内容没关系吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-21 18:44:18 | 显示全部楼层
只爱整活周淑怡 发表于 2020-8-21 18:42
else 是用 super 调用基类的 __setattr__方法 来给 width 赋值为 'square' ,
这句话是啥意思没懂??? ...




这里只有在你else 下面有 self.name=value 才会导致无限递归

你上面代码是不会无限递归,因为把这个注释了

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-21 19:44:38 | 显示全部楼层
Twilight6 发表于 2020-8-21 17:59
因为你不管执行 else 还是 if 代码块都有赋值操作,那么就会无限调用自身的 __setattr__ 方法

就 ...

还有一个就是当name==square的时候是不是 相当于先执行了if的内容赋值成了self.width=5然后又触发了__setattr__方法中的else部分 是这样理解的吗???
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-21 19:47:09 | 显示全部楼层
只爱整活周淑怡 发表于 2020-8-21 19:44
还有一个就是当name==square的时候是不是 相当于先执行了if的内容赋值成了self.width=5然后又触发了__set ...

对 理解正确
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-21 20:50:43 | 显示全部楼层

还有个问题 就是这节的课后作业第2题
>>> class C:
        def __getattr__(self, name):
                print(1)
        def __getattribute__(self, name):
                print(2)
        def __setattr__(self, name, value):
                print(3)
        def __delattr__(self, name):
                print(4)

                
>>> c = C()
>>> c.x = 1
# 位置一,请问这里会显示什么?
>>> print(c.x)
# 位置二,请问这里会显示什么?

我打出
c=C()
c.x
为什么只输出的是2 啊 c.x不是访问了一个不存在的属性吗 那不就应该2 1都打出来吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-21 20:52:32 | 显示全部楼层
只爱整活周淑怡 发表于 2020-8-21 20:50
还有个问题 就是这节的课后作业第2题


>>> c = C()
>>> c.x = 1
# 位置一,请问这里会显示什么?
>>> print(c.x)
# 位置二,请问这里会显示什么?


你前面给 x 赋值为 1 了,也就是说此时这个实例对象里面有属性 x 了

所以只会调用 __getattribute__ 不会调用  __getattr__
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-21 21:03:26 | 显示全部楼层
Twilight6 发表于 2020-8-21 20:52
你前面给 x 赋值为 1 了,也就是说此时这个实例对象里面有属性 x 了

所以只会调用 __getattribu ...

不是啊其实我是这样的一段代码
class C:
        def __getattr__(self, name):
                print(1)
        def __getattribute__(self, name):
                print(2)
        def __setattr__(self, name, value):
                print(3)
        def __delattr__(self, name):
                print(4)

c=C()
c.x
打出来的是2 为啥不是2 1啊c.x不是尚不存在吗那个时候
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-21 21:08:40 | 显示全部楼层
只爱整活周淑怡 发表于 2020-8-21 21:03
不是啊其实我是这样的一段代码

c=C()


先说下 __getattribute__ 的功能,这个是当你访问属性时候会优先调用,如果属性存在,返回属性的值,如果不存在则报错

但是如果类中定义了 __getattr__ 方法,那么这个报错会被这个方法捕获,自动调用 __getattr__ 方法,返回 __getattr__ 设置的内容

而你这里重写了 __getattribute__ 方法,那么原有的 __getattribute__ 方法被你覆盖了,也就不会报错使得 __getattr__ 也就不会被调用

你把代码改成这样就可以了:
class C:
    def __getattr__(self, name):
        print(1)

    def __getattribute__(self, name):
        print(2)
        return super().__getattribute__(name)

    def __setattr__(self, name, value):
        print(3)

    def __delattr__(self, name):
        print(4)

c = C()
c.x
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2020-8-22 00:06:35 | 显示全部楼层
Twilight6 发表于 2020-8-21 21:08
先说下 __getattribute__ 的功能,这个是当你访问属性时候会优先调用,如果属性存在,返回属性的值,如 ...

woc大佬牛啊!!!  小甲鱼什么cylx
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-9-22 21:39:05 | 显示全部楼层
我也是卡在这里难受的一匹
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-4-7 16:35:17 From FishC Mobile | 显示全部楼层
Twilight6 发表于 2020-8-21 18:44
这里只有在你else 下面有 self.name=value 才会导致无限递归

你上面代码是不会无限递归,因为把 ...

你好,调用基类的setattr方法的时候为什么不加self呢?基类为一个变量设置了属性,那这个变量就是子类的吗,这是默认的吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-16 05:10

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表