Python classes losing attributes

馋奶兔 提交于 2019-11-30 13:05:18

PyQT (and therefore maybe also PyGtk or other framework) has the weird behaviour that actually raising an AttributeError somewhere within/below the attribute code will actually make python report that the called attribute on that object does not exist.

There is a (somewhat more official) story somewhere about why this is (and is actually right and understandable behaviour). It has something to do with __getattr__ being defined on a base class: The meganism by which that works is that if calling the attribute on an object results in an AttributeError, the __getattr__ method is called. But that method has no idea what 'attribute' was actually not found. And since the (PyQt.QObject) __getattr__ was designed to implement 'specific' attributes, it decides to raise another AttributeError mentioning the 'called' attribute.

Anyway, what could be is that you are inheriting from an object which uses __getattr__ somewhere and that your own attribute code does call (another) attribute which does, indeed, not exist. What you can do to check this is:

@property
def myproperty:
   try:
      doStuff..
   except AttributeError as e:
      print "Got ya! It is withing the attribute:", repr(e)
      raise ValueError("Got an AttributeError within my attribute!")

Update/Note: Also, if you are implementing __getattr__ yourself on your DeckerGenericList object, be carefull with it for this very same reason! Raising AttributeError's within __getattr__ will most of the time lead to seemingly weird behaviour like this. Note that there is no easy fix: The 'real' AttributeError only carries a string message (and not specificly the actual attribute name), but much more important: the __getattr__ function never sees the original AttributeError in the first place.

Bunyk

Well you can use property and inspect module to trace changes to attribute like this:

import sys
import inspect

def from_where_called():
    info = inspect.getframeinfo(sys._getframe(2))
    code = info.code_context[0] if info.code_context else ''
    return '%s:%s %s' % (info.filename, info.lineno, code)

def add_watched_attribute(name):  
    def attr_watch_get(self):
        value = getattr(self, '_' + name, 'unset')
        print from_where_called(), name, 'is', value
        return value

    def attr_watch_set(self, value):
        print from_where_called(), name, 'set to', value
        setattr(self, '_' + name, value)

    def attr_watch_delete(self):
        print from_where_called(), name, 'deleted'
        delattr(self,'_' + name)

    sys._getframe(1).f_locals[name] = property(
        attr_watch_get, attr_watch_set, attr_watch_delete
    )


class InspectedClass(object):
    add_watched_attribute('victim')

    def __init__(self):
        self.victim = 2

    def kill(self):
        del self.victim


x = InspectedClass()
x.victim = 'asdf'
x.kill()

Or you can use sys.settrace from this answer: https://stackoverflow.com/a/13404866/816449

I think it's a garbage collector bug. I had a similar problem and I think I have narrowed it down to the GC.

Try adding a list extra_references = [] to the top of the module containing the class which loses attributes. In the __init__ method for the class, add the following code:

global extra_references
extra_references.append(self)

That will ensure that there is always a reference to the object outside of GObject.

If the problem goes away, then Python's garbage collector is eating up your object before you're done with it. Smells a lot like this bug (which was supposedly fixed): https://bugzilla.gnome.org/show_bug.cgi?id=92955

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!