鱼C论坛

 找回密码
 立即注册
查看: 936|回复: 16

[已解决]属性访问课后作业

[复制链接]
发表于 2020-6-16 18:01:54 | 显示全部楼层 |阅读模式

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

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

x
关于课后作业第三题,编写一个counter类 用于检测实时对象有多少个属性,我写了下面这个代码,感觉怪怪的,也确实没运行出来,问题出在哪里啊?
class C:
    def __init__(self):
        self.counter=0
    def __setattr__(self,name,value):
        super().__setattr__(name,value)
        self.counter+=1
        super().__setattr__(name,value)
    def __delattr__(self,name):
        super().__delattr__(name)
        self.counter-=1
        super().__delattr__(name)
还有就是,
def __setattr__(self,name,value):
        super().__setattr__(name,value)
        self.counter+=1
        super().__setattr__(name,value)
这种在__setattr__里面遇到赋值的时候  是继续运行完后面的super().__setattr__还是会立即跳出来重新运行 def __setattr__(self,name,value)
最佳答案
2020-6-16 22:27:06
今天的我更强了 发表于 2020-6-16 21:48
对,这个就懂了,但之前问的那个我就迷糊了
class C:
    def __setattr__(self,name,value):

这个不一样,这个 value 是属于外部传入的数,而不属于这个类的,只有这个类里面的才会调用自己类的方法

举个例子:
c = C()
c.test = 10   # 这里的值是外部传入的 也就是 name = test 而  value = 10 
print(c.test)
>>> 11
在 c.test = 10 赋值过程实际上是这样的:
def __setattr__(c,name=test,value=10):
        value+=1    # 10+1 = 11
        super().__setattr__(name,value) # 然后调用父类方法赋值 则 test属性的值为 11
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-6-16 18:32:28 | 显示全部楼层
self.counter+=1 这里不应该是实例属性,而应该改成类属性。

否则你只是给实例的counter属性加了1,而不是类加1.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-6-16 18:59:07 | 显示全部楼层
heidern0612 发表于 2020-6-16 18:32
self.counter+=1 这里不应该是实例属性,而应该改成类属性。

否则你只是给实例的counter属性加了1,而 ...

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

使用道具 举报

发表于 2020-6-16 20:41:55 | 显示全部楼层

self这里指的是你类的实例对象。

也就是说,你实例化的时候,传的值也包括实例本身,也就是self。

所以你不能self里的count +1,而是应该在类里面加1.

也就是说你需要在init里面加个count +=1 ,而不是实例出来的对象+=1.

那样的话,这个self.count就是跟实例绑定了,它就只是实例的属性,而不是类的属性加1了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-16 20:54:42 | 显示全部楼层


其他部分不用看,主要错误是再 __setattr__ 这
def __setattr__(self,name,value):
        super().__setattr__(name,value)
        self.counter+=1
这个函数我们只看这个部分都看出来已经是个死循环了,因为你实例化时候先__init__ 自动调用 self.counter=0

而 self.counter=0 会触发__setattr__方法,__setattr__方法进入后调用父类 进行对 self.counter=0 的赋值

然后 self.counter+=1 这个可以看成 self.counter = self.counter + 1 ,这里又再次赋值,又会调用自己 __setattr__ 然后进行 调用父类方法进行再次调用父类进行赋值self.counter = self.counter + 1 以此进入死循环
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-6-16 20:58:20 | 显示全部楼层
heidern0612 发表于 2020-6-16 20:41
self这里指的是你类的实例对象。

也就是说,你实例化的时候,传的值也包括实例本身,也就是self。

好像有些明白了 那第二个问题呢?求指教   谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-16 20:59:11 | 显示全部楼层

RecursionError: maximum recursion depth exceeded while calling a Python object


这个是函数的报错内容,意思就是超出系统最大的递归次数了,实际上就是无限递归了

所以你的这个代码并不能解决问题,我记得小甲鱼下节课或者下下节课就会有再课后习题那解决这个的办法
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-16 21:01:10 | 显示全部楼层
本帖最后由 Twilight6 于 2020-6-16 21:04 编辑
heidern0612 发表于 2020-6-16 20:41
self这里指的是你类的实例对象。

也就是说,你实例化的时候,传的值也包括实例本身,也就是self。


应该主要不是您说的这个错误吧,小甲鱼这颗是为了让我们知道重写 setattr 时候需要注意初始化的赋值会调用自身

而自身属性还未赋值成功就提前 + 1 导致的报错问题
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-6-16 21:01:11 | 显示全部楼层
Twilight6 发表于 2020-6-16 20:59
这个是函数的报错内容,意思就是超出系统最大的递归次数了,实际上就是无限递归了

所以你的这个代 ...

请问第二个问题呢? 会继续运行完还是会立即跳出来重新运行?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-16 21:03:06 | 显示全部楼层
今天的我更强了 发表于 2020-6-16 21:01
请问第二个问题呢? 会继续运行完还是会立即跳出来重新运行?

第二个问题已经在 5 L 说了 ,你赋值第一次就开始进入无限递归了 而且没有出口不可能会执行到第二个的 super().__setattr__(name,value)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-16 21:14:00 | 显示全部楼层
Twilight6 发表于 2020-6-16 21:01
应该主要不是您说的这个错误吧,小甲鱼这颗是为了让我们知道重写 setattr 时候需要注意初始化的赋值会 ...

嗯嗯,我没看课后题。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-16 21:16:41 | 显示全部楼层
今天的我更强了 发表于 2020-6-16 21:01
请问第二个问题呢? 会继续运行完还是会立即跳出来重新运行?

这里只留 __setattr__ 方法以便观察:
def __setattr__(self,name,value):
    super().__setattr__(name,value)
    self.counter+=1
    super().__setattr__(name,value)

第一次 __init__ 实例化时候 self.counter=0 赋值自动调用 __setattr__ 方法然后运行第一个 super().__setattr__(name,value) ,成功将 self.counter 赋值为 0  然后执行 self.counter+=1

而 self.counter+=1 可以看成 self.counter = self.counter + 1  则赋值又开始自动调用 __setattr__ 方法 这个时候开始第一次递归

进入 __setattr__ 方法 运行到方法第一行 super().__setattr__(name,value) 成功赋值 self.counter = self.counter + 1 然后又执行下面的  self.counter+=1

而 self.counter+=1 可以看成 self.counter = self.counter + 1  则赋值又开始自动调用 __setattr__ 方法 这个时候开始第二次递归

......
...
...
..
.
.

最后报错:
RecursionError: maximum recursion depth exceeded while calling a Python object

递归超出最大限度!


这样可以理解了吧?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-6-16 21:48:24 | 显示全部楼层
Twilight6 发表于 2020-6-16 21:16
这里只留 __setattr__ 方法以便观察:

对,这个就懂了,但之前问的那个我就迷糊了
class C:
    def __setattr__(self,name,value):
        value+=1
        super().__setattr__(name,value)
这个代码,设置参数之后执行,首先遇到vlaue=value+1,然后又遇到赋值,又开始调用 def __setattr__(self,name,value) 这样不也就会无线循环下去,为什么会运行成功?  
不好意思 纯小白  问题比较多
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-16 22:27:06 | 显示全部楼层    本楼为最佳答案   
今天的我更强了 发表于 2020-6-16 21:48
对,这个就懂了,但之前问的那个我就迷糊了
class C:
    def __setattr__(self,name,value):

这个不一样,这个 value 是属于外部传入的数,而不属于这个类的,只有这个类里面的才会调用自己类的方法

举个例子:
c = C()
c.test = 10   # 这里的值是外部传入的 也就是 name = test 而  value = 10 
print(c.test)
>>> 11
在 c.test = 10 赋值过程实际上是这样的:
def __setattr__(c,name=test,value=10):
        value+=1    # 10+1 = 11
        super().__setattr__(name,value) # 然后调用父类方法赋值 则 test属性的值为 11
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-6-16 22:40:59 | 显示全部楼层
Twilight6 发表于 2020-6-16 22:27
这个不一样,这个 value 是属于外部传入的数,而不属于这个类的,只有这个类里面的才会调用自己类的方法
...

也就是这个value+=1调用的是objec里的 __setattr__,而不是我自己定义的def__setattr__  这样理解对吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-16 22:44:08 | 显示全部楼层
今天的我更强了 发表于 2020-6-16 22:40
也就是这个value+=1调用的是objec里的 __setattr__,而不是我自己定义的def__setattr__  这样理解对吗?

嗯~差不多这个意思嘿嘿~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2020-6-16 22:48:32 | 显示全部楼层
Twilight6 发表于 2020-6-16 22:44
嗯~差不多这个意思嘿嘿~

谢谢大佬 感激不尽
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-20 16:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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