davidmou 发表于 2023-8-10 15:35:27

__set__的小问题

class MyDes:
    def __init__(self, initval=None, name=None):
      self.val = initval
      self.name = name

    def __get__(self, instance, owner):
      print("正在获取变量:", self.name)
      return self.val

    def __set__(self, instance, value):
      print("正在修改变量:", self.name)
      super().__setattr__(self.name,value)
      

    def __delete__(self, instance):
      print("正在删除变量:", self.name)
      print("噢~这个变量没法删除~")


class Test:
    x = MyDes(10, 'x')


class MyDes:
    def __init__(self, initval=None, name=None):
      self.val = initval
      self.name = name

    def __get__(self, instance, owner):
      print("正在获取变量:", self.name)
      return self.val

    def __set__(self, instance, value):
      print("正在修改变量:", self.name)
      self.val =value
      

    def __delete__(self, instance):
      print("正在删除变量:", self.name)
      print("噢~这个变量没法删除~")


class Test:
    x = MyDes(10, 'x')



为什么两种代码相差这么大,能帮解释一下吗
为什么第二种代码不会有无限递归错误,self.val = value 不会再触发__set__(self,instance,value)吗
在帮忙解释一下__set__ 和__setattr__的区别
再解释一下

isdkz 发表于 2023-8-10 15:35:44

第一种代码中,在__set__方法中使用了super().__setattr__(self.name,value)来设置属性的值。这会触发父类的__setattr__方法,而父类的__setattr__方法又会调用__set__方法,从而导致无限递归错误。

第二种代码中,直接将属性的值赋给self.val,而没有调用父类的__setattr__方法。因此,不会再次触发__set__方法,也就避免了无限递归错误。

__set__和__setattr__的区别在于:
· __set__是描述符(descriptor)协议中的方法,用于在访问属性时进行拦截和处理。它只能在描述符类中定义,通过实例对象访问属性时才会被调用。
· __setattr__是对象的特殊方法,用于设置对象的属性值。它可以在任何类中定义,通过实例对象设置属性值时会被调用。

总结起来,__set__是描述符类中用于拦截属性设置的方法,而__setattr__是对象的特殊方法,用于设置属性值。两者的调用时机和使用场景不同。

陶远航 发表于 2023-8-10 15:35:45

这两种代码相差很大,因为第一种代码中的__set__方法调用了super().__setattr__(self.name, value)来修改属性值,而super()会调用父类的__setattr__方法,从而避免了无限递归错误。

在第二种代码中,__set__方法直接使用self.val = value来修改属性值,这不会触发__set__方法的递归调用。这是因为__set__方法中的self.val = value是对实例属性进行赋值操作,而不是调用__set__方法来修改属性值。

__set__和__setattr__的区别在于:

· __set__是描述符协议中定义的特殊方法,用于控制属性赋值时的行为。它只能定义在描述符类中,并且可以通过属性访问方式来调用,例如instance.attr = value。
· __setattr__是对象的特殊方法,用于给对象的属性赋值时的行为。它可以定义在普通类或描述符类中,并且可以通过属性赋值方式来调用,例如instance.attr = value。

总结起来,__set__是描述符类中用于控制属性设置过程的方法,而__setattr__是对象中用于控制属性设置过程的方法。
如果问题已经解决,请设置最佳答案

学习编程中的Ben 发表于 2023-8-10 15:35:45

第一种代码中,在__set__方法内部使用了super().__setattr__(self.name, value)来设置属性值。这里使用了super()函数调用父类的__setattr__方法,而不是直接通过self.val = value赋值操作。

对于第二种代码,__set__方法直接使用self.val = value来设置属性值,没有调用父类的__setattr__方法。因此,不会发生无限递归错误。

区别解释如下:

- __set__方法:定义了当尝试给descriptor所在的属性赋值时的行为。在设置属性值时,__set__方法会被调用。
- __setattr__方法:定义了当尝试给对象的属性赋值时的行为。它适用于所有属性,而不仅仅是descriptor。

两者的区别在于调用场景和功能:

- __set__方法是在descriptor被设置为另一个类的属性时被调用,可以对属性赋值进行特定的处理和限制。
- __setattr__方法是在对象的属性被赋值时被调用,无论该属性是否是descriptor,它都会被触发。可以用于实现一般的属性赋值逻辑,但需要注意避免无限递归的情况。

以下是修改后的代码示例:

class MyDes:
    def __init__(self, initval=None, name=None):
      self.val = initval
      self.name = name

    def __get__(self, instance, owner):
      print("正在获取变量:", self.name)
      return self.val

    def __set__(self, instance, value):
      print("正在修改变量:", self.name)
      self.val = value

    def __delete__(self, instance):
      print("正在删除变量:", self.name)
      print("噢~这个变量没法删除~")

class Test:
    x = MyDes(10, 'x')


请记住,在代码示例中进行了适当的格式化和缩进。

如果回答对你有帮助,请给我一个最佳答案!{:10_254:}{:10_254:}{:10_254:}
页: [1]
查看完整版本: __set__的小问题