Python中的方法继承

4 投票
2 回答
8177 浏览
提问于 2025-05-01 02:22

我有一个父类和两个子类。这个父类是一个抽象基类,它有一个叫做combine的方法,这个方法被子类继承了。但是每个子类对combine的实现方式不同,主要体现在参数的数量上,所以它们各自的方法需要的参数数量也不一样。在Python中,当一个子类继承了一个方法并需要重新实现它时,重新实现的方法必须在参数上完全一致。有没有什么办法可以解决这个问题?也就是说,继承的方法可以有动态的参数组合吗?

暂无标签

2 个回答

3

正如其他回答所示,对于普通类来说,子类中重写的继承方法的签名可以与父类中的不同。

即使父类是一个抽象基类,这种情况也是一样的:

import abc

class Foo:
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def bar(self, x, y):
        return x + y

class ChildFoo(Foo):
    def bar(self, x):
        return super(self.__class__, self).bar(x, 3)

class DumbFoo(Foo):
    def bar(self):
        return "derp derp derp"

cf = ChildFoo()
print cf.bar(5)

df = DumbFoo()
print df.bar()

不必要的复杂绕道

在Python的元类中,尝试限制重写方法的能力,使得它们的参数签名必须与基类匹配,这是一项有趣的练习。下面是一个尝试的例子。

注意:我并不认为这是一个好的工程思路,而且我没有花时间去处理一些细节,所以下面的代码可能还有一些小问题,可以让它更高效或者其他什么。

import types
import inspect

def strict(func):
    """Add some info for functions having strict signature.
    """
    arg_sig = inspect.getargspec(func)
    func.is_strict = True
    func.arg_signature = arg_sig
    return func


class StrictSignature(type):
    def __new__(cls, name, bases, attrs):
        func_types = (types.MethodType,) # include types.FunctionType?

        # Check each attribute in the class being created.
        for attr_name, attr_value in attrs.iteritems():
            if isinstance(attr_value, func_types):

                # Check every base for @strict functions.
                for base in bases:
                    base_attr = base.__dict__.get(attr_name)
                    base_attr_is_function = isinstance(base_attr, func_types)
                    base_attr_is_strict = hasattr(base_attr, "is_strict")

                    # Assert that inspected signatures match.
                    if base_attr_is_function and base_attr_is_strict:
                        assert (inspect.getargspec(attr_value) == 
                                base_attr.arg_signature)

        # If everything passed, create the class.
        return super(StrictSignature, cls).__new__(cls, name, bases, attrs)



# Make a base class to try out strictness
class Base:
    __metaclass__ = StrictSignature

    @strict
    def foo(self, a, b, c="blah"):
        return a + b + len(c)

    def bar(self, x, y, z):
        return x


#####
# Now try to make some classes inheriting from Base.
#####
class GoodChild(Base):

    # Was declared strict, better match the signature.
    def foo(self, a, b, c="blah"):
        return c

    # Was never declared as strict, so no rules!
    def bar(im_a_little, teapot):
        return teapot/2


# These below can't even be created. Uncomment and try to run the file
# and see. It's not just that you can't instantiate them, you can't
# even get the *class object* defined at class creation time.
#
#class WrongChild(Base):
#    def foo(self, a):
#        return super(self.__class__, self).foo(a, 5)
#
#class BadChild(Base):
#    def foo(self, a, b, c="halb"):
#        return super(self.__class__, self).foo(a, b, c)

需要注意的是,就像Python中大多数“严格”或“私有”类型的想法一样,你仍然可以在一个“好的类”上随意修改函数,而这些修改后的函数不需要满足签名的约束。

# Instance level
gc = GoodChild()
gc.foo = lambda self=gc: "Haha, I changed the signature!"

# Class level
GoodChild.foo = lambda self: "Haha, I changed the signature!"

即使你在元类中增加更多复杂性,检查类的__dict__中任何方法类型属性的更新,并在类被修改时不断进行assert语句的检查,你仍然可以使用type.__setattr__来绕过自定义行为,直接设置一个属性。

在这些情况下,我想象杰夫·高布伦(Jeff Goldblum)饰演的伊恩·马尔科姆(Ian Malcolm)在《侏罗纪公园》中,面无表情地看着你说:“同意的成年人,呃,总会找到办法……”

4

这段代码展示了被重写的方法的签名是可以很容易地改变的。

class Parent(object):
    def foo(self, number):
        for _ in range(number):
            print "Hello from parent"



class Child(Parent):
    def foo(self, number, greeting):
        for _ in range(number):
            print greeting


class GrandChild(Child):
    def foo(self):
        super(GrandChild,self).foo(1, "hey")


p = Parent()
p.foo(3)

c = Child()
c.foo(2, "Hi")

g = GrandChild()
g.foo()

撰写回答