How can I find out why/when a Python object loses

2019-04-11 18:06发布

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 in ManagerWindowMenu.__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.

标签: python pygtk
3条回答
我想做一个坏孩纸
2楼-- · 2019-04-11 18:38

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.

查看更多
Root(大扎)
3楼-- · 2019-04-11 18:46

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.

查看更多
萌系小妹纸
4楼-- · 2019-04-11 18:49

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:

worker = SearchWorker()

I presume that once that handler exited something odd happened to the object behind the worker reference. Changing the creation of SearchWorker to:

self.worker = SearchWorker()

solved my problem.

查看更多
登录 后发表回答