6

でアクセスしようとしたときに評価されない属性を遅延させるデコレータを作成することは可能hasattr()ですか? 私はそれを怠惰にする方法を考え出しましたが、hasattr()時期尚早に評価します。例えば、

class lazyattribute:
    # Magic.

class A:
    @lazyattribute
    def bar(self):
      print("Computing")
      return 5

>>> a = A()
>>> print(a.bar)
'Computing'
5
>>> print(a.bar)
5
>>> b = A()
>>> hasattr(b, 'bar') 
'Computing'
5
# Wanted output: 5
4

5 に答える 5

4

するのは難しいかもしれません。hasattr ドキュメントから:

hasattr(オブジェクト、名前)

引数はオブジェクトと文字列です。文字列がオブジェクトの属性の 1 つの名前である場合、結果は True になり、そうでない場合は False になります。(これは、 getattr(object, name) を呼び出して、例外が発生するかどうかを確認することで実装されます。 )

属性はメソッドによって動的に生成される可能性がある__getattr__ため、その存在を確実に確認する方法は他にありません。あなたの特別な状況では、辞書を明示的にテストするだけで十分でしょう:

any('bar' in d for d in (b.__dict__, b.__class__.__dict__))
于 2009-08-17T07:40:27.147 に答える
2

これまで誰も対処していないように見えることは、おそらく最善の方法は を使用しないことhasattr()です。代わりに、EAFP (許可よりも許しを求める方が簡単) を選択します。

try:
    x = foo.bar
except AttributeError:
    # what went in your else-block
    ...
else:
    # what went in your if hasattr(foo, "bar") block
    ...

これは明らかにドロップインの代替品ではなく、少し移動する必要があるかもしれませんが、おそらく「最も優れた」ソリューションです (もちろん、主観的には)。

于 2009-08-18T03:21:54.793 に答える
0

問題は、をhasattr使用getattrすると、属性が常に評価されるようになることですhasattr。魔法のコードを投稿すると、 orlazyattributeを必要としない属性の存在をテストする別の方法を誰かが提案できることを願っています。のヘルプを参照してください:hasattrgetattrhasattr

>>> help(hasattr)
Help on built-in function hasattr in module __builtin__:

hasattr(...)
    hasattr(object, name) -> bool

    Return whether the object has an attribute with the given name.
    (This is done by calling getattr(object, name) and catching exceptions.)
于 2009-08-17T07:37:25.970 に答える
0

なぜこのようなものが必要なのか、興味があります。hasattr「計算関数」を呼び出すことになった場合は、そうです。とにかく、あなたの財産はどれだけ怠惰である必要がありますか?

それでも、呼び出し元の関数の名前を調べるという、かなり洗練されていない方法があります。もう少しうまくコーディングできるかもしれませんが、真剣に使用するべきではないと思います。

import inspect

class lazyattribute(object):
    def __init__(self, func):
        self.func = func

    def __get__(self, obj, kls=None):
        if obj is None or inspect.stack()[1][4][0].startswith('hasattr'):
            return None
        value = self.func(obj)
        setattr(obj, self.func.__name__, value)
        return value

class Foo(object):
    @lazyattribute
    def bar(self):
        return 42
于 2009-08-18T04:16:43.190 に答える
-2

修正は少しハックですが、次のもので構成されています

  1. hasattrの名前を変更します(たとえば_hasattr)
  2. 次のようにhasattrを再バインドします。


   def hasattr(obj, name):
     try:
       return obj._hasattr(name) or _hasattr(obj, name)
     except:
       return _hasattr(obj, name)

  1. すべてのレイジー属性名(つまり lazyAttrArrayの名前)が入力されているデータ構造(つまり、配列)をチェックして、クラスメソッド_hasattrを実装します。

  2. 最後に、どういうわけか、@ lazyattributeデコレータにアイテムをある種の構造(上記の配列など)に追加させ、_hasattrを呼び出すと、その構造を調べます。

    • これは、自分でデコレータを作成したことがないため、どのように実装するかがよくわからないステップです。
于 2009-08-17T08:04:15.977 に答える