setattr问题
关于属性访问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__方法是什么内容呢好像之前没有提到过诶 本帖最后由 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__方法是什么内容呢?
在对一个属性设置值的时候,就会自动调到这个函数,每个设置值的方式都会进入这个方法,然后给对应变量设置对应的值。
Twilight6 发表于 2020-8-21 17:59
因为你不管执行 else 还是 if 代码块都有赋值操作,那么就会无限调用自身的 __setattr__ 方法
就 ...
else 是用 super 调用基类的 __setattr__方法 来给 width 赋值为 'square' ,
这句话是啥意思没懂???当我没有令 实例对象.square=value 的时候不是跟else内容没关系吗? 只爱整活周淑怡 发表于 2020-8-21 18:42
else 是用 super 调用基类的 __setattr__方法 来给 width 赋值为 'square' ,
这句话是啥意思没懂??? ...
这里只有在你else 下面有 self.name=value 才会导致无限递归
你上面代码是不会无限递归,因为把这个注释了
Twilight6 发表于 2020-8-21 17:59
因为你不管执行 else 还是 if 代码块都有赋值操作,那么就会无限调用自身的 __setattr__ 方法
就 ...
还有一个就是当name==square的时候是不是 相当于先执行了if的内容赋值成了self.width=5然后又触发了__setattr__方法中的else部分 是这样理解的吗??? 只爱整活周淑怡 发表于 2020-8-21 19:44
还有一个就是当name==square的时候是不是 相当于先执行了if的内容赋值成了self.width=5然后又触发了__set ...
对 理解正确 Twilight6 发表于 2020-8-21 19:47
对 理解正确
还有个问题 就是这节的课后作业第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都打出来吗
只爱整活周淑怡 发表于 2020-8-21 20:50
还有个问题 就是这节的课后作业第2题
>>> c = C()
>>> c.x = 1
# 位置一,请问这里会显示什么?
>>> print(c.x)
# 位置二,请问这里会显示什么?
你前面给 x 赋值为 1 了,也就是说此时这个实例对象里面有属性 x 了
所以只会调用 __getattribute__ 不会调用__getattr__ 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不是尚不存在吗那个时候 只爱整活周淑怡 发表于 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 Twilight6 发表于 2020-8-21 21:08
先说下 __getattribute__ 的功能,这个是当你访问属性时候会优先调用,如果属性存在,返回属性的值,如 ...
woc大佬牛啊!!!小甲鱼什么cylx 我也是卡在这里难受的一匹 Twilight6 发表于 2020-8-21 18:44
这里只有在你else 下面有 self.name=value 才会导致无限递归
你上面代码是不会无限递归,因为把 ...
你好,调用基类的setattr方法的时候为什么不加self呢?基类为一个变量设置了属性,那这个变量就是子类的吗,这是默认的吗?
页:
[1]