我有一个特殊的python问题。在执行我的gtk python应用程序的过程中,我的一些类对象神秘地丢失了属性,导致程序的某些功能中断。
很难理解为什么会发生这种情况 - 我从不故意删除属性,并且有问题的类继承自我自己编写的类(而不是其他类)。
我可以通过重复执行某个操作来触发问题(例如,生成对add_card
方法的多次调用 - 通过疯狂点击或打开文件,导致add_card
被调用20或所以时间)
我真的很茫然,我希望我能提供更多有用的信息给你。
什么可能导致python对象丢失属性?
EDIT,Re。问题:
以下是与“我失去的两个属性”相关的示例回溯:
Traceback (most recent call last):
File "lib/genericlist.py", line 90, in cursor_changed
if self.viewer:
AttributeError: 'DeckerRunnerList' object has no attribute 'viewer'
Traceback (most recent call last):
File "lib/genericlist.py", line 100, in row_activated
selection = self.TABLE_NAME+"&&"+text
AttributeError: 'DeckerRunnerList' object has no attribute 'TABLE_NAME'
以下是他们设置的地方:
class DeckerGenericList(object):
def __init__(self, database, viewer=None, deck=None):
super(DeckerGenericList, self).__init__()
self.database = database
self.viewer = viewer
self.deck = deck
#TABLE_NAME is set in the subclass constructor
这个特殊的子类不会将其称为超类__init__
,因此属性集在子类中重复:
class DeckerRunnerList(DeckerGenericList):
def __init__(self, database, viewer=None, deck=None):
self.database = database
self.viewer = viewer
self.deck = deck
self.TABLE_NAME = "runners"
DeckerGenericList的所有其他子类都有相同的问题,它们都是这样定义的:
class DeckerGearList(DeckerGenericList):
def __init__(self, database, viewer=None, deck=None):
self.TABLE_NAME = "gear"
#... some other class attributes
super(DeckerGearList, self).__init__(database, viewer=viewer, deck=deck)
答案 0 :(得分:3)
PyQT(也许也可能是PyGtk或其他框架)有一种奇怪的行为,实际上在属性代码内/下的某处引发了AttributeError,实际上会让python报告该对象上的被调用属性不存在。
有一个(某种程度上更官方的)故事,关于为什么这是(并且实际上是正确和可理解的行为)。它与在基类上定义的__getattr__有关:它的工作原理是,如果调用对象上的属性导致AttributeError,则调用__getattr__方法。但是那种方法并不知道实际上找不到什么“属性”。由于(PyQt.QObject)__getattr__旨在实现“特定”属性,因此它决定引发另一个提到“被调用”属性的AttributeError。
无论如何,可能是你继承了一个在某处使用__getattr__并且你自己的属性代码调用(另一个)确实不存在的属性的对象。您可以做的是检查:
@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!")
更新/注意:此外,如果您在DeckerGenericList对象上自己实现__getattr__,请谨慎使用它,原因同样如此!在__getattr__中引发AttributeError将大部分时间导致看似奇怪的行为。请注意,没有简单的修复:'real'NameError只携带一个字符串消息(而不是特定的实际属性名称),但更重要的是:__ getattr__函数从不首先看到原始的AttributeError。
答案 1 :(得分:1)
您可以使用属性和检查模块来跟踪对属性的更改,如下所示:
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()
或者您可以使用此答案中的sys.settrace:https://stackoverflow.com/a/13404866/816449
答案 2 :(得分:0)
我认为这是一个垃圾收集器错误。我遇到了类似的问题,我想我已将其缩小到GC。
尝试将列表extra_references = []
添加到包含失去属性的类的模块顶部。在类的__init__
方法中,添加以下代码:
global extra_references
extra_references.append(self)
这将确保始终存在对GObject之外的对象的引用。
如果问题消失了,那么Python的垃圾收集器会在你完成之前吃掉你的对象。闻起来很像这个bug(据说已修复):https://bugzilla.gnome.org/show_bug.cgi?id=92955