Python中的方法继承
我有一个父类和两个子类。这个父类是一个抽象基类,它有一个叫做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()