鱼C论坛

 找回密码
 立即注册
查看: 1222|回复: 4

[已解决]RuntimeError

[复制链接]
发表于 2020-8-2 23:43:18 | 显示全部楼层 |阅读模式

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

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

x
python 46讲有一道题是创建一个class Mydes
能把对所有的变量的访问/修改/删除记录道record.txt里,我的代码是
  1. import time
  2. class Mydes:
  3.     def __init__(self,name='record.txt'):
  4.         self.file = open('/Users/apple/Desktop/python/'+name,'w')
  5.     def record(self,status,name):                                   #记录下来的方法
  6.         time_list = time.gmtime()
  7.         self.file.write('%s变量于UTC%d年%d月%d日%d时%d分%d秒被%s\n'%(name,time_list[0],time_list[1],time_list[2],time_list[3],time_list[4],time_list[5],status))
  8.         self.file.close()                                           #close()保存
  9.         self.file = open('/Users/apple/Desktop/python/'+name,'a')
  10.     def __getattr__(self,name):
  11.         self.record('读取',name)
  12.         return super().__getattr__(name)
  13.     def __setattr__(self,name,value):
  14.         self.record('修改',name)
  15.         super().__setattr__(name,value)
  16.     def __delattr__(self,name):
  17.         self.record('删除',name)
  18.         super().__delattr__(name)
复制代码

但Ta会循环,于是我在前面加了
  1. import sys
  2. sys.setrecursionlimit(10)
复制代码

Ta好像在__getattr__和record之间循环了
这是为什么,又该怎么改啊
最佳答案
2020-8-3 00:48:58

你造成无限递归的原因是因为你 __init__ 魔法方法初始化 file 参数时候因为是赋值操作,所以会自动调用自身的 __setattr__ 方法

而你 __setattr__ 里面又调用了 record() 函数,又再次 record() 函数里又读取了 self.file 参数 导致触发 __getattr__ 魔法方法

而 __getattr__ 魔法方法里面还调用了 record() 函数,导致无限重复调用自身,而超出递归上限

帮你订正了下错误,顺便改了下代码:

  1. import time
  2. class Mydes:
  3.    
  4.     def __init__(self,name='record.txt'):
  5.         self.file = open('/Users/apple/Desktop/python/'+name,'w')

  6.     def record(self,status,name):
  7.         time_list = time.gmtime()
  8.         self.file.write('%s变量于UTC %d 年 %d 月 %d 日 %d 时 %d 分 %d 秒被%s\n'%(name,time_list[0],time_list[1],time_list[2],time_list[3],time_list[4],time_list[5],status))                                        #close()保存

  9.     def __getattr__(self,name):
  10.         self.record('读取',name)


  11.     def __setattr__(self,name,value):
  12.         if name == 'file':
  13.             super().__setattr__(name,value)
  14.         else:
  15.             self.record('修改',name)
  16.             super().__setattr__(name,value)

  17.     def __delattr__(self,name):
  18.         self.record('删除',name)
  19.         super().__delattr__(name)
复制代码


Ps:建议写描述符的方法,因为这节课主要是练习你写描述符滴



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

使用道具 举报

发表于 2020-8-3 00:48:58 | 显示全部楼层    本楼为最佳答案   

你造成无限递归的原因是因为你 __init__ 魔法方法初始化 file 参数时候因为是赋值操作,所以会自动调用自身的 __setattr__ 方法

而你 __setattr__ 里面又调用了 record() 函数,又再次 record() 函数里又读取了 self.file 参数 导致触发 __getattr__ 魔法方法

而 __getattr__ 魔法方法里面还调用了 record() 函数,导致无限重复调用自身,而超出递归上限

帮你订正了下错误,顺便改了下代码:

  1. import time
  2. class Mydes:
  3.    
  4.     def __init__(self,name='record.txt'):
  5.         self.file = open('/Users/apple/Desktop/python/'+name,'w')

  6.     def record(self,status,name):
  7.         time_list = time.gmtime()
  8.         self.file.write('%s变量于UTC %d 年 %d 月 %d 日 %d 时 %d 分 %d 秒被%s\n'%(name,time_list[0],time_list[1],time_list[2],time_list[3],time_list[4],time_list[5],status))                                        #close()保存

  9.     def __getattr__(self,name):
  10.         self.record('读取',name)


  11.     def __setattr__(self,name,value):
  12.         if name == 'file':
  13.             super().__setattr__(name,value)
  14.         else:
  15.             self.record('修改',name)
  16.             super().__setattr__(name,value)

  17.     def __delattr__(self,name):
  18.         self.record('删除',name)
  19.         super().__delattr__(name)
复制代码


Ps:建议写描述符的方法,因为这节课主要是练习你写描述符滴



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

使用道具 举报

 楼主| 发表于 2020-8-3 06:59:38 | 显示全部楼层
你的代码run后输入
  1. >>> m = Mydes()
  2. >>> m.x = 1
  3. >>> m.x
  4. 1
  5. >>> m.y=2
  6. >>> m.y
  7. 2
  8. >>> del m.x
  9. >>> m.file.close()
复制代码

record.txt里只有
  1. x变量于UTC 2020 年 8 月 2 日 22 时 56 分 18 秒被修改
  2. y变量于UTC 2020 年 8 月 2 日 22 时 56 分 20 秒被修改
  3. x变量于UTC 2020 年 8 月 2 日 22 时 56 分 23 秒被删除
复制代码

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

使用道具 举报

 楼主| 发表于 2020-8-3 07:00:59 | 显示全部楼层
是不是应该用__getattribute__() 或__get__()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-3 08:05:24 | 显示全部楼层
kcal 发表于 2020-8-3 07:00
是不是应该用__getattribute__() 或__get__()


是的,这点昨天晚上还真的疏忽了,__getattr__ 是获取一个不存在的属性时候自动调用,应该改成 __getattrrbute__

关于 __get__ 我上面说了,__get__ 本就是描述符类定义的,这里是叫我们写描述符,但是你是直接写了个类重新里面的方法了

  1. import time

  2. class Mydes:

  3.     def __init__(self,name='record.txt'):
  4.         self.file = open(name,'w',encoding='utf-8')

  5.     def record(self,status,name):
  6.         time_list = time.gmtime()
  7.         self.file.write('%s变量于UTC %d 年 %d 月 %d 日 %d 时 %d 分 %d 秒被%s\n'%(name,time_list[0],time_list[1],time_list[2],time_list[3],time_list[4],time_list[5],status))                                        #close()保存

  8.     def __getattribute__(self,name):
  9.         if name == 'file' or name == 'record':
  10.             return super().__getattribute__(name)
  11.         self.record('读取',name)
  12.         return super().__getattribute__(name)
  13.     def __setattr__(self,name,value):
  14.         if name == 'file':
  15.             super().__setattr__(name,value)
  16.         else:
  17.             self.record('修改',name)
  18.             super().__setattr__(name,value)

  19.     def __delattr__(self,name):
  20.         self.record('删除',name)
  21.         super().__delattr__(name)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-25 16:03

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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