2017-05-31 13 views
1

したがって、私自身のクラスを作成し、__getattribute__関数を書き直したいとします。誰かが定義されていない属性を呼び出すたびに、ランダムなintを生成したい。__dict__またはdir()なしで定義された属性に関する情報を取得する

X = GetAttribute() 
print(X.predefined_attribute) # "First attribute" 
X.attr2 = "Hi" 
print(X.attr2) # "Hi" 
print(X.attr3) # random int 

明らかに、これは再帰を引き起こすので、私はこのようなことを書くことはできません。 __dict__を使用せずに、私は定義された属性に関する情報を取得できますか、

class GetAttribute(object): 
    def __init__(self): 
     self.predefined_attribute = "First attribute" 

    def __getattribute__(self, attr): 
     if attr not in self.__dict__: # the bad line 
      return randint(0, 9999) 
     else: 
      return object.__getattribute__(self, attr) 

+0

:属性は__getattribute__が上AttributeErrorを提起することをルックアップ__getattr__だけと呼ばれています。ただし、* class *を最初にチェックする必要があります。 –

答えて

2

__getattribute__を無効にすることを再検討し、代わりにobject.__getattr__() hookを使用することを強くお勧めします。この方法は、任意の不足している属性のために自動的に呼び出され、dir()または__dict__イントロスペクションとは干渉しません:あなたはあなたの属性のクラスをチェックするために失敗したため、

class GetAttribute(object): 
    def __init__(self): 
     self.predefined_attribute = "First attribute" 

    def __getattr__(self, attr): 
     # self.__dict__ can be used here but is not needed for your 
     # sample usecase. 
     return randint(0, 9999) 

独自の実装には欠陥があります。 __dict__はクラスの記述子であり、self.__dict__にアクセスしようとするとobject.__getattribute__も処理され、無限再帰がトリガーされます。 object.__getattribute__最初にを使用して問題を完全に回避できます。あなたは、これがスローする可能性AttributeError例外をキャッチできます。

def __getattribute__(self, attr): 
    try: 
     return object.__getattribute__(self, attr) 
    except AttributeError: 
     return randint(0, 9999) 

より多くの痛みを伴うパスが再実装descriptor protocolは、試験前に、あなたの__dict__属性を取得するために、次のようになります。

def __getattribute__(self, attr): 
    cls = type(self) 
    # retrieve the __dict__ descriptor, and bind it to the instance 
    __dict__ = cls.__dict__['__dict__'].__get__(self) 
    # test against the instance dictionary and all classes in the MRO 
    if attr not in __dict__ and not any(attr in c.__dict__ for c in cls.__mro__): 
     return randint(0, 9999) 
    return object.__getattribute__(self, attr) 

か、self.__dict__にアクセスすることができましたvia object.__getattribute__(self, '__dict__') MROクラスもテストする必要があります。これはインスタンスの属性も提供するためです。 X.__class__GetAttributeではなく、ランダムな整数を返すことは望ましくありません。

しかし、このユースケースはすでに、より洗練された簡単なオプション__getattr__を実装することでカバーされています。

最後に、object.__getattribute__(self, ...)を使用する代わりに、super().__getattribute__(...)を使用して、クラス階層内で他の__getattribute__フックをスキップしないようにする必要があります。

0

あなたは例がself.__dict__「本物」で取得するために、独自の__getattribute__をバイパスする必要がある場合は、明示的に呼び出すことができます__getattribute__スーパークラス:

if attr not in super().__getattribute__('__dict__'): 

しかし、あなたのケースのために、それはおそらくだろう__getattribute__の代わりに__getattr__を実装するほうが簡単です。あなたの再帰がすべての属性が__dict__` `に住んでいなければならないという仮定によって引き起こされる

def __getattr__(self, name): 
    return randint(0, 9999) 
+0

@MartijnPieters:おっと。一定。 – user2357112

+1

そして 'attr in instanceのテスト。__dict__'は、そのオブジェクトを取得するためにwayが使用されていますが、十分ではありません。 '__getattribute__'が見つけられるが、このように見逃されるインスタンス上で利用可能な他の属性があります。 'instance .__ class__'に似ています。 –

関連する問題