kcal 发表于 2020-8-2 23:43:18

RuntimeError

python 46讲有一道题是创建一个class Mydes
能把对所有的变量的访问/修改/删除记录道record.txt里,我的代码是
import time
class Mydes:
    def __init__(self,name='record.txt'):
      self.file = open('/Users/apple/Desktop/python/'+name,'w')
    def record(self,status,name):                                 #记录下来的方法
      time_list = time.gmtime()
      self.file.write('%s变量于UTC%d年%d月%d日%d时%d分%d秒被%s\n'%(name,time_list,time_list,time_list,time_list,time_list,time_list,status))
      self.file.close()                                           #close()保存
      self.file = open('/Users/apple/Desktop/python/'+name,'a')
    def __getattr__(self,name):
      self.record('读取',name)
      return super().__getattr__(name)
    def __setattr__(self,name,value):
      self.record('修改',name)
      super().__setattr__(name,value)
    def __delattr__(self,name):
      self.record('删除',name)
      super().__delattr__(name)
但Ta会循环,于是我在前面加了
import sys
sys.setrecursionlimit(10)
Ta好像在__getattr__和record之间循环了
这是为什么,又该怎么改啊

Twilight6 发表于 2020-8-3 00:48:58


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

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

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

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

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

    def record(self,status,name):
      time_list = time.gmtime()
      self.file.write('%s变量于UTC %d 年 %d 月 %d 日 %d 时 %d 分 %d 秒被%s\n'%(name,time_list,time_list,time_list,time_list,time_list,time_list,status))                                        #close()保存

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


    def __setattr__(self,name,value):
      if name == 'file':
            super().__setattr__(name,value)
      else:
            self.record('修改',name)
            super().__setattr__(name,value)

    def __delattr__(self,name):
      self.record('删除',name)
      super().__delattr__(name)

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



kcal 发表于 2020-8-3 06:59:38

你的代码run后输入
>>> m = Mydes()
>>> m.x = 1
>>> m.x
1
>>> m.y=2
>>> m.y
2
>>> del m.x
>>> m.file.close()
record.txt里只有x变量于UTC 2020 年 8 月 2 日 22 时 56 分 18 秒被修改
y变量于UTC 2020 年 8 月 2 日 22 时 56 分 20 秒被修改
x变量于UTC 2020 年 8 月 2 日 22 时 56 分 23 秒被删除

被读取没了

kcal 发表于 2020-8-3 07:00:59

是不是应该用__getattribute__() 或__get__()

Twilight6 发表于 2020-8-3 08:05:24

kcal 发表于 2020-8-3 07:00
是不是应该用__getattribute__() 或__get__()


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

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

import time

class Mydes:

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

    def record(self,status,name):
      time_list = time.gmtime()
      self.file.write('%s变量于UTC %d 年 %d 月 %d 日 %d 时 %d 分 %d 秒被%s\n'%(name,time_list,time_list,time_list,time_list,time_list,time_list,status))                                        #close()保存

    def __getattribute__(self,name):
      if name == 'file' or name == 'record':
            return super().__getattribute__(name)
      self.record('读取',name)
      return super().__getattribute__(name)
    def __setattr__(self,name,value):
      if name == 'file':
            super().__setattr__(name,value)
      else:
            self.record('修改',name)
            super().__setattr__(name,value)

    def __delattr__(self,name):
      self.record('删除',name)
      super().__delattr__(name)
页: [1]
查看完整版本: RuntimeError