如何找出 Python 对象丢失属性的原因/时间?
更新2013-02-08
我现在知道为什么我无法在一小段测试代码中重现这个问题了。在小程序中,Python 的垃圾收集器不是很活跃。我认为问题在于 Python 正在收集一些仅在 GObject 中引用的对象。我认为这是涉及此错误的回归,或一个新的类似错误。
我发现了这一点,因为我再次遇到了同样的问题,但是使用我自己的类(仅具有来自 GObject 对象的引用)——这次整个 dict 在对象上被擦除。如果我使用此处的代码来监视消失的属性之一,它不会消失!看来额外的引用保留了属性。这听起来像是垃圾收集器的问题。我通过在初始化期间将对象添加到全局列表中来确认这一点......这也解决了现在出现的问题。
原始问题
我在使用 PyGTK GUI 时遇到一些奇怪的行为。我有一个对象不断丢失大量属性。我试图确定这是否是我的代码、Python 解释器或 PyGTK 中的错误。
我没有调用 delattr()
。我尝试通过使用始终引发异常的代码覆盖 __delattr__() 来检测是否有任何内容正在调用对象的 __delattr__() 方法。我能够重现导致对象丢失其属性的事件,但永远不会引发异常。我不确定是否有另一种方法可以找出哪些函数调用(如果有)导致对象丢失属性。
有问题的对象始终运行良好,直到它突然丢失我试图访问的属性。
在 GUI 中执行一些与丢失属性的对象无关的操作后,属性丢失始终会发生。我偶然发现的;可能还有其他操作导致对象失去其属性。
我已将 print id(self)
添加到访问消失属性的方法中。属性消失前后打印的id是相同的。
关于如何追踪这个问题的根源有什么建议吗?
参考代码如下: (注意:如果/当我想出一个重现该问题的简化测试用例时,我将更新此代码。目前重现该错误所需的总代码太这
是我的对象的类,它失去了它的属性。这显然是真实功能代码的最小化版本,但我用它进行调试,问题仍然出现。
它是我的自定义 MenuBar
类的子类。 请注意,on_file_import__activate()
方法通过父类之一连接到菜单项的信号。
class FluidClassManagerWindowMenu(MenuBar):
menu_items = [("File",("Import",))]
def __init__(self, parent):
# XXX: different name than self.parent to see if it stops disappearing
self._xxx_my_parent = parent
MenuBar.__init__(self, parent)
def __delattr__(self,attr):
# XXX: trying to find the cause for lost attributes
traceback.print_stack()
def on_file_import__activate(self, widget=None, data=None):
# XXX: this is the same before and after the attributes disappear
print id(self)
# XXX: print the list of attributes to see what disappears
print dir(self)
# XXX: this works until the _xxx_my_parent attribute disappears
print self._xxx_my_parent
如果您好奇,这里是我的 MenuBar 类的完整源代码。它是一个 pygtkhelpers SlaveView
,继承自 GObject< /代码>。 pygtkhelpers 委托对上面的 on_file_import__activate 方法进行自动信号连接。
class MenuBar(pygtkhelpers.delegates.SlaveView):
def __init__(self, parent):
SlaveView.__init__(self)
self.parent = parent
def create_ui(self):
menu_bar = gtk.MenuBar()
menu_bar.set_pack_direction(gtk.PACK_DIRECTION_LTR)
for menu_name, items in self.menu_items:
menu = gtk.Menu()
submenu = gtk.MenuItem(menu_name)
submenu.set_submenu(menu)
for item_name in items:
if not item_name:
menu.append(gtk.MenuItem())
continue
menuitem = gtk.MenuItem(item_name)
fixed_item_name = item_name.lower().replace(' ','_')
fixed_menu_name = menu_name.lower().replace(' ','_')
attr_name = '%s_%s' % (fixed_menu_name,fixed_item_name)
# set an attribute like self.edit_vial_layout
# so pygtkhelpers can find the widget to connect the signal from
setattr(self,attr_name,menuitem)
menu.append(menuitem)
menu_bar.append(submenu)
self.vbox = gtk.VBox()
self.vbox.pack_start(menu_bar)
self.vbox.show_all()
self.widget.add(self.vbox)
从对象中消失的属性列表:
'_model'、'_props'、'_toplevel'、'_xxx_my_parent'、'file_import'、'parent'、'slaves'、'testtesttest' , 'vbox', 'widget'
属性 parent
是最初消失的属性;我尝试将其值分配给 _xxx_my_parent
ManagerWindowMenu.__init__()
但它也消失了。我还在 MenuBar.__init__
中添加了一个我从未访问过的新属性,称为 testtesttest
,它也消失了。
Update 2013-02-08
I have an idea now why I haven't been able to reproduce this problem in a small piece of test code. In a small program, Python's garbage collector isn't very active. I believe the problem is that Python is collecting some objects that are only referenced in GObject. I think it's a regression involving this bug, or a new similar bug.
I figured this out because I encountered the same problem again, but with my own class (which has references only from GObject objects) -- this time the entire dict is getting wiped out on the object. Uf I use the code here to monitor one of the attributes that dissappears, it doesn't disappear! It seems the extra reference keeps the attributes around. That smells like a garbage collector problem. I confirmed this by having the object add itself to a global list during initialization... that also fixes the problem as it occurs now.
Original Problem
I am experiencing some bizarre behavior with a PyGTK GUI. I have an object which is consistently losing a large number of attributes. I am trying to determine if this is a bug in my code, the Python interpreter, or PyGTK.
I make no calls to delattr()
. I have tried detecting if anything is calling the __delattr__()
method of my object by overriding __delattr__()
with code that always raises an exception. I am able to reproduce the event which causes the object to lose its attributes but the exception is never raised. I'm not sure of another way to find out what function calls (if any) are causing the object to lose attributes.
The object in question is working perfectly at all times up until it suddenly loses attributes I'm trying to access.
The attribute loss occurs consistently after performing some actions in the GUI that have nothing to do with the object that is losing attributes. I discovered it by accident; there may be other actions that cause the object to lose its attributes.
I have added print id(self)
to the method which access the disappearing attribute. The id that is printed is the same before and after the attribute disappears.
Any suggestions on how to track down the source of this problem?
Reference code below: (Note: I will update this code if/when I come up with a simplified test case that reproduces the problem. Right now the total code required to reproduce the bug is too big to post here.)
Here is the class for my object which loses its attributes. This is obviously a minimized version of the real functional code, but I am using this for debugging and the problem still occurs.
It is a subclass of my custom MenuBar
class.
Note that the on_file_import__activate()
method is connected to the signal for the menu item by one of the parent classes.
class FluidClassManagerWindowMenu(MenuBar):
menu_items = [("File",("Import",))]
def __init__(self, parent):
# XXX: different name than self.parent to see if it stops disappearing
self._xxx_my_parent = parent
MenuBar.__init__(self, parent)
def __delattr__(self,attr):
# XXX: trying to find the cause for lost attributes
traceback.print_stack()
def on_file_import__activate(self, widget=None, data=None):
# XXX: this is the same before and after the attributes disappear
print id(self)
# XXX: print the list of attributes to see what disappears
print dir(self)
# XXX: this works until the _xxx_my_parent attribute disappears
print self._xxx_my_parent
If you're curious, here is the complete source for my MenuBar class. It is a pygtkhelpers SlaveView
, which inherits from GObject
. The pygtkhelpers delegate does the automagic signal connection to the on_file_import__activate
method above.
class MenuBar(pygtkhelpers.delegates.SlaveView):
def __init__(self, parent):
SlaveView.__init__(self)
self.parent = parent
def create_ui(self):
menu_bar = gtk.MenuBar()
menu_bar.set_pack_direction(gtk.PACK_DIRECTION_LTR)
for menu_name, items in self.menu_items:
menu = gtk.Menu()
submenu = gtk.MenuItem(menu_name)
submenu.set_submenu(menu)
for item_name in items:
if not item_name:
menu.append(gtk.MenuItem())
continue
menuitem = gtk.MenuItem(item_name)
fixed_item_name = item_name.lower().replace(' ','_')
fixed_menu_name = menu_name.lower().replace(' ','_')
attr_name = '%s_%s' % (fixed_menu_name,fixed_item_name)
# set an attribute like self.edit_vial_layout
# so pygtkhelpers can find the widget to connect the signal from
setattr(self,attr_name,menuitem)
menu.append(menuitem)
menu_bar.append(submenu)
self.vbox = gtk.VBox()
self.vbox.pack_start(menu_bar)
self.vbox.show_all()
self.widget.add(self.vbox)
List of attributes which disappear from the object:
'_model', '_props', '_toplevel', '_xxx_my_parent', 'file_import', 'parent', 'slaves', 'testtesttest', 'vbox', 'widget'
The attribute parent
is what originally was disappearing; I tried assigning its value to _xxx_my_parent
inManagerWindowMenu.__init__()
but it disappears as well. I also added a new attribute in MenuBar.__init__
that I never access, called testtesttest
, and it disappears too.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
请记住,PyGTK 中的对象通常继承自 GObject。 GObject 框架内可能发生的活动导致您丢失属性。
Keep in mind that objects in PyGTK often inherit from GObject. There is likely activity occuring within the GObject framework that is causing you to lose the attributes.
我有一个非常相似的问题。我有一个类(SearchWorker),它构建了一个小部件,用于在运行时添加到 GUI。在该小部件中,有一个按钮,其“单击”信号连接到 SearchWorker 函数之一。每当“单击”信号被触发时,SearchWorker self 对象的许多属性都会消失。
我在不同类的另一个处理程序中创建 SearchWorker 对象,如下所示:
我认为一旦该处理程序退出,工作者引用后面的对象就会发生一些奇怪的事情。将 SearchWorker 的创建更改为:
解决了我的问题。
I had a very similar problem. I had a class (SearchWorker) that built a widget for adding to the GUI at runtime. In that widget, there was a button whose "clicked" signal was connected to one of the SearchWorker functions. Whenever the "clicked" signal was fired, many of the attributes of the SearchWorker self object were gone.
I was creating the SearchWorker object in another handler of a different class like this:
I presume that once that handler exited something odd happened to the object behind the worker reference. Changing the creation of SearchWorker to:
solved my problem.
多么奇怪啊。顺便说一句,使用
delattr
和__delattr__
调用并不常见,所以我怀疑您是否不单独处理两个不同的对象,在获取一个对象的同时期待另一个对象。另外,这可能不是解释器的问题,如果有问题,它会在低得多的级别崩溃。How strange. BTW, using
delattr
and__delattr__
call is not very common, so I suspect if you are not dealing with two different objects by themselves, getting one while expecting another. Also it may not be a problem with the interpreter, it would crash at much lower level if there was a problem.