在python中委派@classmethods

时间:2013-12-20 00:03:18

标签: python delegation

我需要委派的类来委派@classmethod。这是我尝试过的:

class Foo(object):

    def __init__(self, a):
        self.a = a

    @classmethod
    def from_a(cls, a):
        return cls(a)

class Bar(object):

    def __init__(self, foo):
        elf._foo = foo

    def __getattribute__(self, name):
        return getattr(self._foo, name)

但是,当然这并未定义如何查找Foo的属性(而不是Foo的实例),因此Bar.from_a(5)会引发AttributeError 。虽然当然可以通过在from_a上定义Bar方法或通过调用Bar(Foo.from_a(5))来实例化来明确地执行此操作,但我宁愿隐式地执行此操作。想法?

1 个答案:

答案 0 :(得分:2)

我开始研究我认为使用元类的简单方法,但它实际上相当复杂。你应该在这里做的是让Bar继承Foo,但我会告诉你我想出的是什么:

import types
import functools

def make_delegating_type(delegatee):
    class DelegatingType(type):
        def __getattr__(self, name):
            obj = getattr(delegatee, name)
            if isinstance(obj, (types.FunctionType, types.MethodType)):
                @functools.wraps(obj)
                def wrapper(*args, **kwargs):
                    result = obj(*args, **kwargs)
                    if isinstance(result, delegatee):
                        return self(result)
                    return result
                return wrapper
            return obj
    return DelegatingType

class Foo(object):
    def __init__(self, a): self.a = a

    @classmethod
    def from_a(cls, a): return cls(a)

class Bar(object):
    __metaclass__ = make_delegating_type(Foo)
    def __init__(self, foo): self._foo = foo

    def __getattr__(self, name): return getattr(self._foo, name)

请注意,在3.x中,您会使用class Bar(object, metaclass=make_delegating_type(Foo)代替__metaclass__ = make_delegating_type(Foo)类主体顶部的Bar行。

这是如何工作的。您当前的版本当前将Bar实例上的属性查找委托给Foo的实例,这会使用元类,以便委派 Bar上的属性查找到 class Foo也是如此。不幸的是,它并不像使用返回__getattr__的{​​{1}}定义那么简单,因为如果你查找的属性是一个工厂函数,就像在你的例子中那样你需要一个版本的工厂函数返回委派类型的实例。因此,例如getattr(delegatee, name)应该与Bar.from_a(5)相同,并且使用天真的方法,您将获得Bar(Foo.from_a(5))。这就是为什么有所有逻辑检测属性是函数还是方法,并创建一个检查该函数/方法的返回类型的包装器。

重申一下,我建议您不要使用此代码!这比在Foo.from_a(5)上定义from_aBar继承更复杂来自Bar。但希望这对你来说是一次学习经历,就像我一样。