2014-11-02 140 views
2

我有一個父類和兩個子類。父類是具有方法combine的抽象基類,它被子類繼承。但是每個孩子實現combine與參數角度不同,因此他們各自的方法都採用不同數量的參數。在python中,當一個孩子繼承一個方法並且需要重新實現它時,這個新重新實現的方法必須匹配參數。有沒有解決的辦法?即,繼承的方法可以有動態參數組成?Python方法繼承

謝謝。

+4

請出示一些代碼演示您的問題。沒有要求子類方法具有與超類版本相同的參數簽名(但是,當然,如果*調用超類版本,則必須使用正確的參數調用它)。 – BrenBarn 2014-11-02 02:31:57

+0

爲什麼問一個詳細的問題,但不提供代碼? -_- – 2014-11-02 02:46:22

+0

雖然當然沒有要求子類方法保持相同的簽名,但它似乎是不良設計的症狀。特別是,它肯定違反利斯科夫替代原則。 – sapi 2014-11-02 04:32:06

回答

2

此代碼演示重寫方法的簽名可以輕鬆更改。

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() 
2

至於對方的回答表明了普通班,一個覆蓋繼承方法的簽名可以在孩子比在父母不同。

同樣是真實的,即使父是一個抽象基類:

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__旁路自定義行爲並設置屬性。

在這種情況下,我想傑夫·高布倫伊恩·馬爾科姆從侏羅紀公園,你茫然地看,說「同意的成年人,呃,找到一種方式。」