|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 awp 于 2023-5-30 10:03 编辑
新手求问:
class C:
def __setattr__(self, key, value):
self.key = value # 无限递归
# self.__dict__[key] = value 不会递归
类C造成无限递归。因为__setattr__本身是赋值,函数内部出现赋值,形成无限递归。
为什么self.__dict__[name] = value也是赋值语句,但不会形成无限递归?
同样的问题:
class D:
def __init__(self, data):
self.data = data
def __contains__(self, item):
return item in self.data
类D不会无限递归。但contains本身就是in,而函数内部也出现了in,为什么不无限递归?
还有:
类D可以参考类C的写法,省略掉__init__,这么写么?
class D:
def __contains__(self, data, item):
return item in self.data
首先,我们来讨论关于 __setattr__ 的无限递归问题。当你在Python中定义一个类,并在类中重写 __setattr__ 方法的时候,你基本上就在告诉Python:每次我试图设置这个对象的属性时,我都希望你调用这个方法。因此,如果你在 __setattr__ 方法中再试图设置对象的属性(就像你的例子中那样),那么Python会再次调用 __setattr__ ,形成无限递归。
但是,当你直接操作对象的 __dict__ 属性时,你实际上是在绕过 __setattr__ ,直接在对象的属性字典中设置键/值对。这就是为什么 self.__dict__[key] = value 不会造成无限递归。
关于你的第二个问题,类 D 并不会无限递归,原因是 __contains__ 方法和 in 操作符的逻辑是不同的。 __contains__ 方法定义的是当使用 in 操作符检查一个对象是否包含某个元素时应该做什么。而 in 操作符本身的行为就是调用对象的 __contains__ 方法(如果存在的话)。但在 __contains__ 方法内部使用 in 操作符检查另一个对象(例如 self.data )时,并不会引发递归,因为你检查的对象是不同的。如果你把 return item in self.data 换成 return item in self 一样是会引发无线递归的问题的
对于你的最后一个问题,对于Python类的方法,第一个参数通常被命名为 self ,这是一个传统的约定,用于引用调用该方法的对象本身。而 __contains__ 方法只接受一个额外的参数,即要检查的元素。如果你尝试像你那样定义 __contains__ 方法,Python将会抛出一个TypeError,因为 __contains__ 被调用时只传递了一个参数,但你的定义需要两个。
在你的例子中,你可能需要将 data 定义为类的一个属性,然后在 __contains__ 方法中检查它。例如,你可以这样做:
class D:
def __init__(self, data):
self.data = data
def __contains__(self, item):
return item in self.data
这样,在创建一个 D 对象时,你可以给 data 传值,然后使用 in 操作符检查一个元素是否在 data 中。
|
|