3

Pythonクラスで特別なメソッドを使用して、欠落しているプロパティまたは関数のいずれかを処理するのはかなり簡単ですが__getattr__、両方を同時に処理することはできないようです。

クラスの他の場所で明示的に定義されていない、要求されたプロパティを処理するこの例を考えてみましょう。

class Props:
    def __getattr__(self, attr):
        return 'some_new_value'

>>> p = Props()
>>> p.prop                          # Property get handled
'some_new_value'

>>> p.func('an_arg', kw='keyword')  # Function call NOT handled
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: 'str' object is not callable

次に、クラスの他の場所で明示的に定義されていない関数呼び出しを処理するこの例を検討してください。

class Funcs:
    def __getattr__(self, attr):
        def fn(*args, **kwargs):
            # Do something with the function name and any passed arguments or keywords
            print attr
            print args
            print kwargs
            return 
        return fn

>>> f = Funcs()
>>> f.prop                          # Property get NOT handled
<function fn at 0x10df23b90>

>>> f.func('an_arg', kw='keyword')  # Function call handled
func
('an_arg',)
{'kw': 'keyword'}

問題は、両方のタイプの欠落している属性を同じものでどのように処理する__getattr__かです。要求された属性がプロパティ表記であるか、括弧付きのメソッド表記であるかを検出し、それぞれ値または関数を返す方法は?基本的に、いくつかの欠落しているプロパティ属性といくつかの欠落している関数属性を処理してから、他のすべての場合はデフォルトの動作に頼りたいと思います。

助言?

4

2 に答える 2

3

要求された属性がプロパティ表記であるか、括弧付きのメソッド表記であるかを検出し、それぞれ値または関数を返す方法は?

できません。また、要求されたメソッドがインスタンス、クラス、静的メソッドなどのいずれであるかを判断することもできません。判断できるのは、誰かが読み取りアクセス用の属性を取得しようとしていることだけです。getattribute機構には他に何も渡されないため、コードで使用できるものは他にありません。

したがって、関数または他の種類の値を作成するかどうかを知るための帯域外の方法が必要です。これは実際にはかなり一般的です。実際には、値/関数の区別がある他のオブジェクト(PyObjCを考えてください)をプロキシしいる場合ctypesや、命名規則などがある場合があります。

ただし、どちらの方法でも使用できるオブジェクトをいつでも返すことができます。たとえば、「デフォルトの動作」で属性が整数である場合、または整数を返す関数である場合は、次のように返すことができます。

class Integerizer(object):
    def __init__(self, value):
        self.value = value
    def __int__(self):
        return self.value
    def __call__(self, *args, **kw):
        return self.value
于 2013-01-30T19:59:46.303 に答える
1

返された属性がどのように使用されることを意図していたかを検出する方法はありません。Python オブジェクトのすべては、メソッドを含めて属性です。

>>> class Foo(object):
...     def bar(self): print 'bar called'
...     spam='eggs'
... 
>>> Foo.bar
<unbound method Foo.bar>
>>> Foo.spam
'eggs'

Python は最初に属性 (barまたは) を検索し、それを呼び出すspamつもりであれば(括弧を追加)、Python は属性を検索した後に callable を呼び出します。

>>> foo = Foo()
>>> fbar = foo.bar
>>> fbar()
'bar called'

上記のコードでは、 の参照をbar呼び出しから分離しましたbar

区別がないため__getattr__、返された属性が何に使用されるかを検出できません。

__getattr__通常の属性アクセスが失敗するたびに呼び出されます。次の例montyでは、クラスで定義されているため、__getattr__呼び出されません。と に対してのみ呼び出されbar.ericますbar.john:

>>> class Bar(object):
...     monty = 'python'
...     def __getattr__(self, name):
...         print 'Attribute access for {0}'.format(name)
...         if name == 'eric':
...             return 'idle'
...         raise AttributeError(name)
... 
>>> bar = Bar()
>>> bar.monty
'python'
>>> bar.eric
Attribute access for eric
'idle'
>>> bar.john
Attribute access for john
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in __getattr__
AttributeError: john

呼び出す (呼び出す) ことができるオブジェクトは関数だけではないことに注意してください。メソッドを実装するカスタム クラスは次の__call__ようになります。

>>> class Baz(object):
...    def __call__(self, name):
...        print 'Baz sez: "Hello {0}!"'.format(name)
...
>>> baz = Baz()
>>> baz('John Cleese')
Baz sez: "Hello John Cleese!"

__getattr__さまざまなコンテキストで呼び出して値として使用できる戻りオブジェクトを使用できます。

于 2013-01-30T19:57:19.077 に答える