鱼C论坛

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

[已解决]关于__setattr__()和super().__setattr__()混合使用的问题

[复制链接]
发表于 2023-10-4 12:57:34 | 显示全部楼层 |阅读模式

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

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

x

问题如图所示

程序内部执行顺序的问题

问题参考视频教程:045魔法方法:属性访问.mp4


微信图片_20231004125620.png
最佳答案
2023-10-4 17:23:20
在这里,程序要设置 self.a 和 self.b 的值之后才会打印赋值相同值这一个字符串,
但是, self.a 和 self.b 的设置会先打印两次基类赋值,
因此,基类赋值会在赋值相同值之前。
你可以试试把赋值相同值提到紧跟在 if 的位置,赋值相同值也就会在基类赋值之前了。
class C:
    def __init__(self,q=0,w=0):
        self.a=q
        self.b=w

    def __setattr__(self,name,value):
        if name == "pp":
            self.a=5
            self.b=5
            print("赋值相同值")
        else:
            print("基类赋值")
            super().__setattr__(name,value)

test=C()
test.pp=9
跳过test=C()这一行的运行
运行位置运行代码变量更改注释
16test.pp=9这时候开始调用__setattr__,这行代码等同于
test.__setattr__("pp", 9)
16>6def __setattr__(self, name, value):name = "pp"
value = 9
16>7if name == "pp":这时候 name 就是 "pp"
16>8self.a = 5这时候会再次调用__setattr__,也就是
self.__setattr__("a", 5)
16>8>6def __setattr__(self, name, value):name = "a"
value = 5
16>8>7if name == "pp":这时候 name 是 "a"
16>8>12print("基类赋值")先打印一次基类赋值
16>8>13super().__setattr__(name, value)self.a = 5这时候才成功给 a 赋值
16>9self.a = 5这时候会再次调用__setattr__,也就是
self.__setattr__("b", 5)
16>9>6def __setattr__(self, name, value):name = "b"
value = 5
16>9>7if name == "pp":这时候 name 是 "b"
16>9>12print("基类赋值")又打印一次基类赋值
16>9>13super().__setattr__(name, value)self.b = 5这时候才成功给 b 赋值
16>10print("赋值相同值")这时候才是赋值相同值

本帖被以下淘专辑推荐:

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

使用道具 举报

发表于 2023-10-4 12:57:50 | 显示全部楼层
在Python中,__setattr__()是一个特殊方法,用于设置对象的属性。当我们使用obj.attr = value语法时,实际上是调用了__setattr__()方法。在子类中重写__setattr__()方法时,如果想要调用父类的__setattr__()方法,可以使用super().__setattr__()。这样做的好处是可以避免无限递归的问题。



在给定的代码中,首先创建了一个名为A的类,其中定义了__setattr__()方法。在该方法中,调用了super().__setattr__()方法,这样就可以将属性设置到对象中。接着,创建了一个名为B的类,继承自A类。在B类中,也定义了__setattr__()方法,但是没有调用super().__setattr__()方法。因此,在执行B类的__setattr__()方法时,会一直递归调用自己,导致程序出现死循环。



解决这个问题的方法是在B类的__setattr__()方法中调用super().__setattr__()方法,这样就可以避免无限递归的问题。修改后的代码如下所示:


class A:

    def __setattr__(self, name, value):

        print("A __setattr__")

        super().__setattr__(name, value)



class B(A):

    def __setattr__(self, name, value):

        print("B __setattr__")

        super().__setattr__(name, value)



b = B()

b.x = 10


在这个修改后的代码中,当我们执行b.x = 10语句时,会先调用B类的__setattr__()方法,然后调用A类的__setattr__()方法。这样就可以正确地设置属性,而不会出现死循环的问题。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-10-4 12:58:10 | 显示全部楼层
由于我无法查看图片,我无法直接回答您的问题。但是,我可以为您提供关于__setattr__()super().__setattr__()的一般信息。

__setattr__()是一个特殊的方法,用于在Python类中自定义属性赋值的行为。当您尝试为对象的属性赋值时,Python会自动调用这个方法。例如:
class MyClass:
    def __setattr__(self, name, value):
        print(f"Setting attribute {name} to {value}")
        super().__setattr__(name, value)

obj = MyClass()
obj.x = 10  # 输出 "Setting attribute x to 10"

在这个例子中,我们重写了__setattr__()方法,以便在为属性赋值时输出一条消息。然后,我们使用super().__setattr__()调用父类的__setattr__()方法,以确保属性赋值仍然按预期进行。

super()函数用于调用父类的方法。在这种情况下,我们使用super().__setattr__()来调用object类的__setattr__()方法,因为object是所有Python类的基类。

当您在自定义类中混合使用__setattr__()super().__setattr__()时,请确保您了解这两个方法的作用,以及它们如何影响属性赋值的行为。如果您能提供更多关于您问题的具体信息,我将很高兴为您提供更详细的解答。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-10-4 12:58:21 | 显示全部楼层
[b]关于 __setattr__()super().__setattr__() 混合使用的问题[/b]

首先,我们需要了解 __setattr__()super().__setattr__() 的基本概念。

__setattr__() 是一个特殊的方法,用于在 Python 类中自定义属性赋值的行为。当我们尝试为类的实例设置一个属性时,__setattr__() 方法会被自动调用。

super().__setattr__() 是一种调用父类(或超类)的 __setattr__() 方法的方式。这在子类中重写 __setattr__() 方法时非常有用,因为它允许我们在子类中扩展或修改父类的行为,而不是完全替换它。

由于您没有提供具体的代码示例,我将提供一个简单的示例来说明 __setattr__()super().__setattr__() 的混合使用。
class MyBaseClass:    def __setattr__(self, name, value):        print(f"Setting attribute '{name}' to value '{value}' in MyBaseClass")        super().__setattr__(name, value)class MyDerivedClass(MyBaseClass):    def __setattr__(self, name, value):        print(f"Setting attribute '{name}' to value '{value}' in MyDerivedClass")        super().__setattr__(name, value)obj = MyDerivedClass()obj.some_attr = 42
在这个示例中,我们有两个类:MyBaseClassMyDerivedClassMyDerivedClass 继承自 MyBaseClass。在这两个类中,我们都重写了 __setattr__() 方法,并在其中使用了 super().__setattr__()

当我们创建一个 MyDerivedClass 的实例并尝试为其设置一个属性时,以下操作将发生:

1. MyDerivedClass__setattr__() 方法被调用。
2. 在 MyDerivedClass__setattr__() 方法中,我们使用 super().__setattr__() 调用 MyBaseClass__setattr__() 方法。
3. MyBaseClass__setattr__() 方法被调用,并执行属性赋值。

这个示例展示了如何在子类中使用 super().__setattr__() 来调用父类的 __setattr__() 方法,从而实现属性赋值的自定义行为。希望这个示例能帮助您理解 __setattr__()super().__setattr__() 的混合使用。如果您有具体的代码示例或问题,请随时提供,我将尽力帮助您。

球一个最佳答案谢谢啦!这对我非常重要!
本段回答来自Chat GPT-4,如有错误,多多包涵!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-10-4 17:23:20 | 显示全部楼层    本楼为最佳答案   
在这里,程序要设置 self.a 和 self.b 的值之后才会打印赋值相同值这一个字符串,
但是, self.a 和 self.b 的设置会先打印两次基类赋值,
因此,基类赋值会在赋值相同值之前。
你可以试试把赋值相同值提到紧跟在 if 的位置,赋值相同值也就会在基类赋值之前了。
class C:
    def __init__(self,q=0,w=0):
        self.a=q
        self.b=w

    def __setattr__(self,name,value):
        if name == "pp":
            self.a=5
            self.b=5
            print("赋值相同值")
        else:
            print("基类赋值")
            super().__setattr__(name,value)

test=C()
test.pp=9
跳过test=C()这一行的运行
运行位置运行代码变量更改注释
16test.pp=9这时候开始调用__setattr__,这行代码等同于
test.__setattr__("pp", 9)
16>6def __setattr__(self, name, value):name = "pp"
value = 9
16>7if name == "pp":这时候 name 就是 "pp"
16>8self.a = 5这时候会再次调用__setattr__,也就是
self.__setattr__("a", 5)
16>8>6def __setattr__(self, name, value):name = "a"
value = 5
16>8>7if name == "pp":这时候 name 是 "a"
16>8>12print("基类赋值")先打印一次基类赋值
16>8>13super().__setattr__(name, value)self.a = 5这时候才成功给 a 赋值
16>9self.a = 5这时候会再次调用__setattr__,也就是
self.__setattr__("b", 5)
16>9>6def __setattr__(self, name, value):name = "b"
value = 5
16>9>7if name == "pp":这时候 name 是 "b"
16>9>12print("基类赋值")又打印一次基类赋值
16>9>13super().__setattr__(name, value)self.b = 5这时候才成功给 b 赋值
16>10print("赋值相同值")这时候才是赋值相同值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-29 03:01

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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