Как я могу узнать, почему / когда объект Python теряет атрибуты? - PullRequest
3 голосов
/ 18 марта 2011

Обновление 2013-02-08

Теперь у меня есть идея, почему я не смог воспроизвести эту проблему в небольшом фрагменте тестового кода. В небольшой программе сборщик мусора в Python не очень активен. Я считаю, что проблема в том, что Python собирает некоторые объекты, на которые есть ссылки только в GObject. Я думаю, что это регрессия с участием этой ошибки или новой аналогичной ошибки.

Я понял это, потому что снова столкнулся с той же проблемой, но с моим собственным классом (который имеет ссылки только из объектов GObject) - на этот раз весь dict стирается на объекте. Если я использую код здесь , чтобы отслеживать один из атрибутов, который исчезает, он не исчезает! Кажется, дополнительная ссылка хранит атрибуты. Это пахнет проблемой сборщика мусора. Я подтвердил это, добавив объект в глобальный список во время инициализации ... это также устраняет проблему, как это происходит сейчас.

Оригинальная проблема

У меня странное поведение с графическим интерфейсом PyGTK. У меня есть объект, который постоянно теряет большое количество атрибутов. Я пытаюсь определить, является ли это ошибкой в ​​моем коде, интерпретаторе Python или PyGTK.

Я не звоню на delattr(). Я попытался определить, вызывает ли что-нибудь метод __delattr__() моего объекта, переопределив __delattr__() кодом, который всегда вызывает исключение. Я могу воспроизвести событие, которое приводит к тому, что объект теряет свои атрибуты, но исключение никогда не возникает. Я не уверен в другом способе выяснить, какие вызовы функций (если таковые имеются) вызывают потерю атрибутов объекта.

Рассматриваемый объект работает идеально все время, пока он внезапно не потеряет атрибуты, к которым я пытаюсь получить доступ.

Потеря атрибута происходит последовательно после выполнения некоторых действий в графическом интерфейсе, которые не имеют ничего общего с объектом, который теряет атрибуты. Я обнаружил это случайно; могут быть другие действия, которые приводят к тому, что объект теряет свои атрибуты.

Я добавил print id(self) к методу, который обращается к исчезающему атрибуту. Идентифицируемый идентификатор до и после исчезновения атрибута.

Любые предложения о том, как отследить источник этой проблемы?

Ссылочный код ниже: (Примечание. Я обновлю этот код, если / когда придумаю упрощенный тестовый пример, который воспроизводит проблему. Прямо сейчас весь код, необходимый для воспроизведения ошибки слишком велик для размещения здесь.)

Вот класс для моего объекта, который теряет свои атрибуты. Это, очевидно, минимизированная версия реального функционального кода, но я использую это для отладки, и проблема все еще возникает.

Это подкласс моего пользовательского 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, и он тоже исчезает.

Ответы [ 3 ]

2 голосов
/ 18 марта 2011

Имейте в виду, что объекты в PyGTK часто наследуются от GObject. Вероятно, в среде GObject происходит активность, которая приводит к потере атрибутов.

2 голосов
/ 06 июля 2012

У меня была очень похожая проблема.У меня был класс (SearchWorker), который создавал виджет для добавления в GUI во время выполнения.В этом виджете была кнопка, чей сигнал «нажал» был связан с одной из функций SearchWorker.Всякий раз, когда срабатывал сигнал «нажал», многие атрибуты собственного объекта SearchWorker пропадали.

Я создавал объект SearchWorker в другом обработчике другого класса, например:

worker = SearchWorker()

Я предполагаю, что как только этот обработчик завершил работу, что-то странное случилось с объектом за рабочей ссылкой.Изменение создания SearchWorker на:

self.worker = SearchWorker()

решило мою проблему.

0 голосов
/ 18 марта 2011

Как странно. Кстати, использование вызовов delattr и __delattr__ не очень распространено, поэтому я подозреваю, что вы не имеете дело с двумя разными объектами сами по себе, получая один, ожидая другого. Кроме того, это может не быть проблемой с переводчиком, он может аварийно завершить работу на более низком уровне, если возникнет проблема.

...