更新2013-02-08
我现在知道为什么我无法在一小段测试代码中重现这个问题。在一个小程序中,Python的垃圾收集器不是很活跃。我相信问题是Python正在收集一些仅在GObject中引用的对象。我认为这是一个涉及this bug的回归,或者是一个新的类似错误。
我认为这是因为我再次遇到了同样的问题,但是我自己的类(它只引用了GObject对象) - 这次整个 dict 在这个对象上消失了。如果我使用代码here来监控其中一个消失的属性,它就不会消失!似乎额外的引用保持了属性。闻起来像垃圾收集器问题。我通过在初始化期间将对象添加到全局列表来确认这一点...这也解决了现在发生的问题。
我在使用PyGTK GUI时遇到了一些奇怪的行为。我有一个一直失去大量属性的对象。我试图确定这是否是我的代码,Python解释器或PyGTK中的错误。
我没有打电话给delattr()
。我已经尝试通过使用始终引发异常的代码覆盖__delattr__()
来检测是否正在调用我的对象的__delattr__()
方法。我能够重现导致对象失去其属性的事件,但永远不会引发异常。我不确定另一种方法来找出哪些函数调用(如果有的话)导致对象丢失属性。
有问题的对象在任何时候都能正常工作,直到它突然失去我想要访问的属性。
在GUI中执行与失去属性的对象无关的某些操作后,属性丢失始终如一。我偶然发现了它;可能存在导致对象失去其属性的其他操作。
我已将print id(self)
添加到访问消失属性的方法中。在属性消失之前和之后打印的id是相同的。
有关如何追查此问题根源的任何建议?
下面的参考代码: (注意:如果/当我想出一个可以重现问题的简化测试用例时,我会更新此代码。现在需要重现的代码。 bug太大了,不能在这里发帖。)
这是我的对象的类失去了它的属性。这显然是实际功能代码的最小化版本,但我使用它进行调试,问题仍然存在。
它是我的自定义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
,它也消失了。
答案 0 :(得分:2)
请记住,PyGTK中的对象经常从GObject继承。 GObject框架内可能会发生导致您丢失属性的活动。
答案 1 :(得分:2)
我有一个非常类似的问题。我有一个类(SearchWorker),它构建了一个小部件,用于在运行时添加到GUI。在该窗口小部件中,有一个按钮,其“点击”信号连接到其中一个SearchWorker功能。每当触发“clicked”信号时,SearchWorker自身对象的许多属性都消失了。
我在另一个类的另一个处理程序中创建了SearchWorker对象,如下所示:
worker = SearchWorker()
我假设一旦那个处理程序退出了一些奇怪的事情发生在worker引用后面的对象上。将SearchWorker的创建更改为:
self.worker = SearchWorker()
解决了我的问题。
答案 2 :(得分:0)
delattr
和__delattr__
调用并不常见,所以我怀疑你是不是自己处理两个不同的对象,而是期待另一个对象。此外,它可能不是解释器的问题,如果出现问题,它会在更低的级别崩溃。