Kivy中Dropdown对象内存地址与is判断异常问题咨询
问题描述
在Kivy的kv文件中定义了如下CustomDropDown组件:
<CustomDropDown>: myadd_curve_button: add_curve_button MyButton: id: add_curve_button text: 'Add Curve'
根据Kivy机制,kv中定义的Dropdown子组件会被放入其container容器内。为了遍历container的子组件并保留上述kv中定义的按钮,在CustomDropDown类的reset_children方法中编写了如下代码:
def reset_children(self): print(f'button address with id(): {id(self.myadd_curve_button):x}') print(f'child address with id:() {id(self.container.children[0]):x}') print(f'self.myadd_curve_button: {self.myadd_curve_button}') for child in self.container.children: print(f'child: {child}') if not( child is self.myadd_curve_button): self.remove_widget(child) del child
执行后得到如下输出:
button address with id(): 7f9bd5b62bd0 child address with id:() 7f9bd5b5db50 self.myadd_curve_button: <__main__.MyButton object at 0x7f9bd5b5db50> child: <__main__.MyButton object at 0x7f9bd5b5db50>
发现直接打印对象时显示的内存地址一致,但调用id()获取的地址却不同,导致is判断返回False。按默认__str__()实现,显示的地址应与id()返回的十六进制地址一致,请问这是为什么?
问题原因与解决办法
原因
问题出在Kivy的属性代理机制上:
- 如果你在
CustomDropDown类中用ObjectProperty声明了myadd_curve_button,Kivy会为该属性创建一个代理对象。 - 当你访问
self.myadd_curve_button时,得到的是这个代理对象,而非真正的MyButton实例。但代理对象的__str__方法会显示被代理的真实Widget的内存地址,所以打印时看起来和容器里的子项地址一致。 - 而
id()函数获取的是代理对象自身的内存地址,和真实Widget的地址自然不同,这就导致is判断(比较对象身份)返回False。
解决办法
有两种可靠的方式来实现你的需求:
- 通过Widget的id属性判断:直接检查子组件的
id是否为add_curve_button,代码修改如下:
def reset_children(self): for child in self.container.children[:]: # 遍历副本避免修改列表时出错 if child.id != 'add_curve_button': self.remove_widget(child)
- 获取代理背后的真实对象:如果一定要用对象身份判断,可通过代理对象的
__self__属性获取真实Widget实例:
def reset_children(self): real_button = self.myadd_curve_button.__self__ for child in self.container.children[:]: if child is not real_button: self.remove_widget(child)
注意:遍历容器子组件时,最好遍历children列表的副本(如children[:]),避免在删除子项时导致遍历异常。
内容的提问来源于stack exchange,提问作者Erik Iverson
相关产品推荐
相关产品推荐

