Python继承,方法重载和装饰

时间:2016-06-18 00:47:39

标签: python inheritance

我有一个继承自A:

的B类
class A():
    def do_something(self, x):
        """Prints x."""
        print(x)

class B(A):
    def something_else(self, x):
        print("This isn't the same.")

我想做一些事情:

  • 我希望B.do_something继承A.do_something的文档字符串。我认为functools.wraps是推荐的解决方案:是吗?
  • 我们假设A有一些返回A实例的方法。如果我从B调用这些方法,我希望他们返回B的实例。到目前为止,我手动重载每个函数。

    def method_of_A(self, *args, **kwargs):
        return A(super(self.__class__, self).method_of_A(*args, **kwargs))
    

    可能有更好的方法 - 特别是考虑到我必须为大量课程做这件事。是否有相同的方法来检查是否在B中定义了一个函数,如果没有,但在A中可用,是否将它装饰/包装以返回B的实例?编辑:我无法更改A的代码库。

  • 是否存在Py2和Py3兼容的解决方案?

非常感谢任何建议。

2 个答案:

答案 0 :(得分:2)

是的,您可以使用functools.wraps复制函数名称和docstring。您可以使用self.__class__

返回当前类的实例
class A(object):

    def func(self):
        return self.__class__()

class B(A):

    @functools.wraps(A.func)
    def func(self):
        return super(B, self).func()

>>> b = B()
>>> obj = b.return_object()
>>> print type(obj)
"<class '__main__.B'>"
  

是否有同样的方法来检查是否在B中定义了一个函数,如果没有,但在A中可用,是否将它装饰/包装以返回B的实例?

您可以使用metaclasses执行此操作,假设A尚未使用您无法继承的自定义元类(例如,它仅在C和尚未暴露于python)。在python 2和3中,使用元类的方式略有不同。

class MetaB(type):

    def __new__(cls, name, bases, attrs):
        if A in bases:
            for attr, value in A.__dict__.items():
                if isinstance(value, types.FunctionType) and attr not in attrs:
                    new_func = MyMeta.make_wrapper_func(value)
                    attrs[attr] = new_func

        return super(MetaB, cls).__new__(cls, name, bases, attrs)

    @staticmethod
    def make_wrapper_func(func):

        @functools.wraps(func)
        def _func(self, *args, **kwargs):
            value = func(self, *args, **kwargs)
            if isinstance(value, A):
                value = self.__class__(value)
            return value

        return _func



class B(A):
    __metaclass__ = MetaB

    ...

在python 3中,元类的使用方式略有不同

class B(A, metaclass=MetaB):
    ...

这假设您可以通过将B()的实例传递给它的构造函数(即A())来创建return self.__class__(value)类型的对象。这只是猜测。我必须知道更多关于你的对象知道如何将A对象转换为B对象,但一般方法是相同的。此解决方案也仅适用于常规类方法。它不会用于classmethodsstaticmethods等其他类型的描述符对象或其他类型的描述符对象。你当然可以让它适用于所有这些,你的元类只需要更复杂一点。

答案 1 :(得分:-1)

  

假设有一些A的方法返回A的实例。如果我从B调用这些方法,我希望它们返回B的实例。到目前为止,我正在手动重载每个函数。 / p>

使用classmethod。

class A(object):
    @classmethod
    def f(cls):
        return cls

当b(B的实例)将调用f时,它将返回B.