19

あるオブジェクトを別のオブジェクトにラップしています。"Wrapper" は、 をオーバーライドすることによって、"Wrapped" オブジェクトの属性にアクセスします__getattr__。これは、サブクラスの属性をオーバーライドする必要があるまではうまく機能し、super().

から属性に直接アクセスできます__getattr__が、なぜ機能しsuper()ないのですか?

class Wrapped(object):
    def __init__(self, value):
        self.value = value

    def hello_world(self):
        print 'hello world', self.value

class Wrapper(object):
    def __init__(self, obj):
        self.wrapped_obj = obj

    def __getattr__(self, name):
        if name in self.__dict__:
            return getattr(self, name)
        else:
            return getattr(self.wrapped_obj, name)

class Subclass(Wrapper):
    def __init__(self, obj):
        super(Subclass, self).__init__(obj)

    def hello_world(self):
        # this works
        func = super(Subclass, self).__getattr__('hello_world')()
        # this doesn't
        super(Subclass, self).hello_world()

a = Wrapped(2)
b = Subclass(a)
b.hello_world()
4

1 に答える 1

15

これによると、 super は などの「フック」関数の暗黙的な呼び出しを許可しません__getattr__。なぜこのように実装されているのかはわかりませんが (おそらく十分な理由があり、スーパーオブジェクトにはカスタム__getattribute____get__メソッドがそのままあるため、すでに十分に混乱しています)、それはまさにその通りのようです。

編集:この投稿は、物事を少し片付けているようです。__getattribute__問題は、関数を暗黙的に呼び出すときに無視されることによって引き起こされる余分な間接層であるように見えます。することfoo.xはと同等です

foo.__getattr__(x)

__getattribute__(メソッドが定義されておらず、 x が に含まれていないと仮定しfoo.__dict__ます) ただし、次と同等ではありません

foo.__getattribute__('__getattr__')(x)

super はプロキシ オブジェクトを返すため、余分な間接レイヤーがあり、これが失敗の原因になります。

PS関数のself.__dict__チェック__getattr__は完全に不要です。__getattr__属性が辞書にまだ存在しない場合にのみ呼び出されます。(__getattribute__常に呼び出されるようにしたい場合に使用しますが、単純なようなものでもif name in self.__dict__無限再帰が発生するため、十分に注意する必要があります。

于 2012-08-21T03:31:14.487 に答える