3

今日、パイソンに噛まれました。実装内のオブジェクトの属性にアクセスしようとしています__setattr__- 方法がわかりません。これは私がこれまでに試したことです:

class Test1(object):
    def __init__(self):
        self.blub = 'hi1'

    def __setattr__(self, name, value):
        print self.blub

class Test2(object):
    def __init__(self):
        self.blub = 'hi2'

    def __setattr__(self, name, value):
        print object.__getattr__(self, 'blub')

class Test3(object):
    def __init__(self):
        self.blub = 'hi3'

    def __setattr__(self, name, value):
        print object.__getattribute__(self, 'blub')

class Test4(object):
    def __init__(self):
        self.blub = 'hi4'

    def __setattr__(self, name, value):
        print self.__getattr__('blub')

class Test5(object):
    def __init__(self):
        self.blub = 'hi5'

    def __setattr__(self, name, value):
        print self.__getattribute__('blub')

class Test6(object):
    def __init__(self):
        self.blub = 'hi6'

    def __setattr__(self, name, value):
        print self.__dict__['blub']

テスト:

try:
    TestX().bip = 'bap'
except Exception as ex:
    print ex

X~から~1まで6

出力:

'Test1' object has no attribute 'blub'
type object 'object' has no attribute '__getattr__'
'Test3' object has no attribute 'blub'
'Test4' object has no attribute '__getattr__'
'Test5' object has no attribute 'blub'
'blub'

助言がありますか?

4

5 に答える 5

4

内部では、どの呼び出し__init__を設定しようとしているためです。何も設定せずにアクセス(および印刷)しようとしますが、何も見つからず、エラーが発生します。これをチェックして:blub__setattr__blub

>>> class Test2(object):
  def __init__(self):
    print "__init__ called"
    self.blub = 'hi2'
    print "blub was set"

  def __setattr__(self, name, value):
    print "__setattr__ called"
    print self.blub


>>> Test2()
__init__ called
__setattr__ called

Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    Test2()
  File "<pyshell#9>", line 4, in __init__
    self.blub = 'hi2'
  File "<pyshell#9>", line 9, in __setattr__
    print self.blub
AttributeError: 'Test2' object has no attribute 'blub'
>>> 
于 2013-08-13T08:40:09.247 に答える
2

OP、あなたは私たちにすべての話をしていません。次のようなコードを実行しただけではありません。

TestX().bip = 'bap'

次のようなコードを実行しました。

try:
    TestX().bip = 'bap'
except Exception as ex:
    print ex

大きな違いがあります。なぜ聞くの?さて、あなたの出力は一見するとそれが機能していることを示しているように見えますTest6. なぜ機能しているように見えるのですか?コードを読むと、それが機能するはずがありません。ソース コードを詳しく調べると、動作してhi6た場合はではなくが出力されているはずであることがわかり'blub'ます。

例外を調べるために、print ex行にブレークポイントを置きます。pdb

(Pdb) ex
KeyError('blub',)
(Pdb) print ex
'blub'

何らかの理由で期待どおりにprint ex印刷されませんが、それが機能しているように見えたのです。KeyError: blub'blub'Test6

それで、私たちはそれを片付けました。今後、重要になる可能性があるため、このようなコードを省略しないでください。

他のすべての回答は、印刷しようとしている属性を設定していないこと、およびこれが問題であることを正しく指摘しています。この回答を受け入れる前に、以前に受け入れた回答は、代わりに次の解決策を規定しています。

def __setattr__(self, name, value):
    self.__dict__[name] = value
    print self.__dict__[name]

このソリューションは確かに機能しますが、適切な設計ではありません。これは、ある時点で基本クラスを変更したい場合があり、属性を設定および/または取得するときにその基本クラスに重大な副作用が生じる可能性があるか、属性がまったく保存されない可能性があるためself.__dict__です! をいじらないようにする方が良い設計__dict__です。

正しい解決策は、親__setattr__メソッドを呼び出すことです。これは、python 2.x の構文が間違っていますが、少なくとも 1 つの他の回答によって提案されました。これが私がそれを行う方法です:

def __setattr__(self, name, value):
    super(Test6, self).__setattr__(name, value)
    print getattr(self, name)

ご覧のとおり、属性を動的に検索するgetattr代わりに使用しています。直接__dict__使用する場合とは異なり、これは必要に応じてorを呼び出します。__dict__self.__getattr__self.__getattribute__

于 2013-08-13T09:14:00.007 に答える
1
print self.__dict__['blub']

blubどちらが正しいかを出力します。次のように、Python はそれを行わないため、最初に新しい値を設定する必要があります。

def __setattr__(self, name, value):
    self.__dict__[name] = value
    print self.__dict__[name]

次に、test6.blub = 'test'印刷する必要がありますtest

編集:

@Lauritz で提案されているように、使用することもできます

def __setattr__(self, name, value):
    super(Test6, self).__setattr__(name, value)
    print self.__dict__[name]

親関数を呼び出すため、スーパークラスに既に__setattr__関数がある場合はオーバーライドされません。

于 2013-08-13T08:37:06.970 に答える
1

実際に属性を設定することはない__setattr__ので、もちろんオブジェクトには属性がありません。

def __setattr__(self, name, value):
    self.name = value
        # this doesn't work, since it calls itself (the __setattr__)

def __setattr__(self, name, value):
    super().__setattr__(name, value)
        # call the default implementation directly in Py 3.x

def __setattr__(self, name, value):
    super(TestX, self).__setattr__(name, value) # for Python 2.x

もちろん、これを単独で行うのは何の役にも立ちません。通常、何らかの機能を追加したり、何らかの条件、デバッグ印刷、キャッシュなど、必要なものを追加したりします。

于 2013-08-13T08:37:19.987 に答える
1

__setattr__クラスで機能するため、オーバーライドするときは、実際に属性を設定する必要があります...そうしないと、存在しません...例:

object.__setattr__(self, name, value)

したがって、__init__あなたがそれを行うself.blub = 'hi'と、実際にはノーオペレーションになります。

于 2013-08-13T08:40:28.903 に答える