davidmou 发表于 2023-8-9 15:39:34

求找两个代码的不同

class Counter:
    def __init__(self):
      self.count = 0

    def __setattr__(self, name, value):
      if name != 'count':
            self.count += 1
      return super().__setattr__(name, value)

    def __delattr__(self, name):
      self.count -= 1
      


class Counter:
    def __init__(self):
      self.count = 0
    def __setattr__(self,name,value):
      self.count += 1
      return super().__setattr__(name,value)
    def __delattr__(self,name):
      self.count -= 1




为什么两个代码结果完全不同
出现了什么错误呢,上面的会出现属性错误,而下面的却不会

isdkz 发表于 2023-8-9 15:39:48

这两段代码在实现上看起来非常相似,但是它们的行为却有很大的差异。问题出在第一个代码段的 __setattr__ 方法中的一个细微错误。

在第一个代码段中, __setattr__ 方法中的 return super().__setattr__(name, value) 语句被放置在了if语句的内部。这意味着,当 name 不等于'count'时, self.count 会被加1,然后 super().__setattr__(name, value) 会被调用。这个调用将会触发 __setattr__ 方法的递归调用,因为我们正在试图设置一个属性,而这个属性的名字不是'count'。这样就导致了无限递归,最终会引发 RecursionError 。

而在第二个代码段中, __setattr__ 方法中的 return super().__setattr__(name, value) 语句被放置在了if语句的外部。这意味着,当 name 不等于'count'时, self.count 会被加1,然后 super().__setattr__(name, value) 不会被调用,从而避免了递归调用的问题。

因此,第一个代码段会导致属性错误,而第二个代码段则不会出现这个问题。

陶远航 发表于 2023-8-9 15:39:54

这两段代码的主要区别在于第一个代码块中的__setattr__方法中有一个额外的判断条件 if name != 'count':,而第二个代码块中没有这个判断条件。

第一个代码块中的判断条件 if name != 'count': 意味着只有当设置的属性名不等于 'count' 时,计数器 count 才会增加。这样做的目的是防止在设置计数器属性时重复计数。

相比之下,第二个代码块中的__setattr__方法没有这个判断条件,因此在设置任意属性时都会使计数器 count 增加。

这就是为什么两段代码的结果完全不同的原因。第一个代码块中的判断条件 if name != 'count': 导致只有除了计数器属性之外的属性改变时,计数器才会增加。而第二个代码块中没有这个判断条件,所以在设置任意属性时都会导致计数器增加。

至于属性错误的问题,是在第一个代码块的 __delattr__ 方法中可能出现的。该方法中的 self.count -= 1 在删除任意属性时都会执行,包括 count 属性本身。这样会导致计数器 count 减少过多,可能引发属性错误。

希望以上解释能够回答您的问题!如果还有其他疑问,请继续提问。
如果问题已经解决,请设置最佳答案

学习编程中的Ben 发表于 2023-8-9 15:39:57

本帖最后由 学习编程中的Ben 于 2023-8-9 15:43 编辑

问题理解:

您想知道为什么两个给定的代码会产生完全不同的结果以及出现了什么错误。您指出上面的代码会出现属性错误,而下面的代码却不会。

解决方案:

让我们逐步比较这两段代码,找出它们之间的不同之处。

上面的代码:

class Counter:
    def __init__(self):
      self.count = 0

    def __setattr__(self, name, value):
      if name != 'count':
            self.count += 1
      return super().__setattr__(name, value)

    def __delattr__(self, name):
      self.count -= 1

下面的代码:

class Counter:
    def __init__(self):
      self.count = 0

    def __setattr__(self, name, value):
      self.count += 1
      return super().__setattr__(name, value)

    def __delattr__(self, name):
      self.count -= 1

这两段代码的主要区别在于__setattr__方法中的条件判断。

在上面的代码中,__setattr__方法中的条件判断是 if name != 'count',如果属性名不是count,则递增self.count的计数器。这意味着除了设置count属性外的任何其他属性更改都会递增self.count的值。

而在下面的代码中,__setattr__方法没有条件判断,每当设置属性时都会递增self.count计数器。

因此,这两段代码的结果会产生不同。在上面的代码中,只有当设置非 count 属性时才会增加计数器的值,而下面的代码中,无论设置什么属性都会增加计数器的值。

至于为什么上面的代码会出现属性错误,是因为在__init__方法中初始化了count属性,但在__setattr__方法中尝试递增count属性的值之前,count属性还不存在。这会导致属性错误。

为了解决这个问题,我们可以在__init__方法中使用super().__setattr__('count', 0)来初始化count属性为0。

以下是修改后的代码:

class Counter:
    def __init__(self):
      super().__setattr__('count', 0)

    def __setattr__(self, name, value):
      self.count += 1
      return super().__setattr__(name, value)

    def __delattr__(self, name):
      self.count -= 1

现在,运行修改后的代码将不会出现属性错误,并且会得到预期的结果。

希望以上解答对您有所帮助。如果您还有其他问题,请随时提问。

如果回答对你有帮助,请给我一个最佳答案!{:10_254:}{:10_254:}{:10_254:}

学习编程中的Ben 发表于 2023-8-9 15:44:15

给个最佳答案呗!求你了!!!{:10_254:}

歌者文明清理员 发表于 2023-8-9 15:45:05

学习编程中的Ben 发表于 2023-8-9 15:44
给个最佳答案呗!求你了!!!

臭不要脸

学习编程中的Ben 发表于 2023-8-9 15:48:15

歌者文明清理员 发表于 2023-8-9 15:45
臭不要脸

谢谢夸奖{:10_256:}

davidmou 发表于 2023-8-9 20:50:37

学习编程中的Ben 发表于 2023-8-9 15:39
问题理解:

您想知道为什么两个给定的代码会产生完全不同的结果以及出现了什么错误。您指出上面的代码会 ...

为什么在__init__方法中初始化了count属性,但在__setattr__方法中尝试递增count属性的值之前,count属性还不存在。这会导致属性错误。,能否帮忙解释一下。

学习编程中的Ben 发表于 2023-8-9 21:04:51

davidmou 发表于 2023-8-9 20:50
为什么在__init__方法中初始化了count属性,但在__setattr__方法中尝试递增count属性的值之前,count属性 ...

在 __init__ 方法中,我们确实初始化了 count 属性,但是在 __init__ 方法执行完毕之后,对象的属性字典中并不会立即包含该属性。

在 Python 中,对象的属性字典是保存对象所有属性的地方。当我们访问对象的属性时,Python 会在属性字典中查找属性名。如果属性名存在于字典中,就返回对应的值;如果不存在,则引发 AttributeError 错误。

在 __init__ 方法中,我们直接将 count 属性添加到对象的属性字典中,因此在初始化方法执行完毕后,我们可以正常访问和修改 count 属性。

但是,在 __setattr__ 方法中,当我们尝试设置属性时,实际上会调用 __setattr__ 方法本身来完成属性设置操作。这意味着在方法执行过程中,属性字典可能还没有包含该属性,因此会出现属性错误。

为了解决这个问题,我们可以通过在 __setattr__ 方法中使用 super().__setattr__(name, value) 将属性添加到属性字典中,而不是直接设置属性字典。这样,属性会被正确添加到字典中,并且能够在方法中使用。

hcll706 发表于 2023-8-9 22:16:05

class Counter:
    def __init__(self):
      self.count = 0

    def __setattr__(self, name, value):
      if name != 'count':
            self.count += 1
      return super().__setattr__(name, value)

    def __delattr__(self, name):
      self.count -= 1

class Counter:
    def __init__(self):
      self.count = 0
    def __setattr__(self,name,value):
      self.count += 1
      return super().__setattr__(name,value)
    def __delattr__(self,name):
      self.count -= 1
----------------------------------------------------------------------------------------------------------------
先说第一段 代码:假设不增加新的 attr ,那么 if name != 'count' 就永远不执行.发挥拦截作用的是 最后一句 return super().__setattr__(name, value).
第二段代码:   init 初始化失败!代码在init 赋值时 会调用 __setattr__方法 . self.name+=1 这句无法执行(原因是:self.name=self.name+1,注意 self.name+1 是在右边的,是个<右值>,self没有初始化成功,何来的slef.name+1?)
总结:self.name+=1 这个代码 只有在初始化 成功之后 才可以用.第一段 代码 初始化成功(依赖super的setattr) 存在self.name; 假设给个新属性 p.age=20, self.name+1 成功执行.

hcll706 发表于 2023-8-9 22:17:11

hcll706 发表于 2023-8-9 22:16
class Counter:
    def __init__(self):
      self.count = 0


更正一下是self.count+1
页: [1]
查看完整版本: 求找两个代码的不同