10

私は独特のPythonの問題を抱えています。gtk python アプリケーションの実行中に、クラス オブジェクトの一部が不思議なことに属性を失い、プログラムの機能の一部が壊れます。

なぜこれが起こるのかを理解するのは難しいです.私は意図的に属性を削除したことはありません.問題のクラスは私が書いたクラスから継承しています.

特定のアクションを繰り返し実行することで問題を引き起こすことができます(たとえば、add_cardメソッドへの多くの呼び出しを生成します-狂ったようにクリックするか、ファイルを開くことadd_cardで、20回ほど呼び出されます)

私は本当に途方に暮れており、あなたに提供するのに役立つと思われる情報がもっとあればいいのにと思います.

Python オブジェクトが属性を失う原因は何ですか?

編集、Re。質問:

以下は、「失う」2 つの属性に関連するトレースバックの例です。

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)
4

3 に答える 3

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!")

更新/注: また、__getattr__ を自分で DeckerGenericList オブジェクトに実装している場合は、これとまったく同じ理由で注意してください! __getattr__ 内で AttributeError を発生させると、ほとんどの場合、このような一見奇妙な動作につながります。簡単な修正はないことに注意してください: 「本当の」 AttributeError は文字列メッセージ (具体的には実際の属性名ではない) のみを運びますが、もっと重要です: __getattr__ 関数は元の AttributeError を最初から見ません。

于 2012-11-28T10:30:07.100 に答える
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

于 2012-11-22T21:12:54.657 に答える
0

ガベージコレクターのバグだと思います。同様の問題があり、GCに絞り込んだと思います。

extra_references = []属性を失うクラスを含むモジュールの先頭にリストを追加してみてください。クラスの__init__メソッドに、次のコードを追加します。

global extra_references
extra_references.append(self)

これにより、GObject の外部にあるオブジェクトへの参照が常に存在することが保証されます。

問題が解決した場合は、Python のガベージ コレクターがオブジェクトを使い果たす前に食べ尽くしています。このバグのような匂いがします (修正されたと思われます): https://bugzilla.gnome.org/show_bug.cgi?id=92955

于 2013-02-08T21:31:53.070 に答える