2011-07-27 38 views
5

Khi tôi gọi phương thức đệ quy lớp cơ sở từ lớp dẫn xuất, cuộc gọi đệ quy được thực hiện dựa vào phương thức dẫn xuất, thay vì phương thức lớp cơ sở. Làm thế nào tôi có thể tránh được rằng mà không sửa đổi việc triển khai lớp cơ sở (trong ví dụ lớp A)?ghi đè phương thức đệ quy trong python

Dưới đây là một ví dụ

class A(object): 
    # recursive method 
    def f(self, x): 
     print x, 
     if x < 0: 
      self.f(x+1) 
     if x > 0: 
      self.f(x-1) 
     if x == 0: 
      print "" 

class B(A): 
    # Override method 
    def f(self): 
     # do some pretty cool stuff 
     super(B, self).f(25) 

if __name__ == "__main__": 
    A().f(5) 
    B().f() 

Tôi đã có đầu ra này:

5 4 3 2 1 0 
25 
Traceback (most recent call last): 
    File "./test.py", line 19, in <module> 
    B().f() 
    File "./test.py", line 15, in f 
    super(B, self).f(25) 
    File "./test.py", line 9, in f 
    self.f(x-1) 
    TypeError: f() takes exactly 1 argument (2 given) 

Cảm ơn trước,

+1

Chỉ cần thay đổi tên chức năng của bạn ... – JBernardo

Trả lời

4

Name mangling là công cụ cho công việc này. Điều này sẽ trông như thế này trong trường hợp của bạn:

class A(object): 
    # recursive method 
    def f(self, x): 
     print x, 
     if x < 0: 
      self.__f(x+1) 
     if x > 0: 
      self.__f(x-1) 
     if x == 0: 
      print "" 

    __f = f 

class B(A): 
    # Override method 
    def f(self): 
     # do some pretty cool stuff 
     super(B, self).f(25) 

Giải thích từ các tài liệu liên quan:

Bất kỳ định dạng __spam (ít nhất là hai dấu gạch hàng đầu, nhiều nhất một dấu gạch dưới) là bản văn thay thế bằng _classname__spam, trong đó tên lớp là tên lớp hiện tại với dấu gạch dưới hàng đầu bị tước.

+0

Tt thường là một ý tưởng tốt để bảo vệ việc triển khai và hiển thị giao diện của bạn. Nó dẫn đến rất nhiều 'def f (self, x): self._f (x)', nhưng nó làm cho nó dễ dàng hơn để tránh những vấn đề này. – cwallenpoole

+3

Nên sử dụng tên mangling tốt nhất nếu có thể. – awatts

+0

ok cảm ơn. Nhưng đó là một ví dụ giả, những gì tôi có thể làm gì nếu tôi không thể truy cập vào lớp A thực hiện bởi vì nó trong mô-đun nhập khẩu? – Albert

0

Tôi khuyên bạn nên đổi tên các phương thức riêng lẻ là f thành phương thức riêng tư được gọi là _f và có tái sử dụng. Sau đó, bạn có thể giới thiệu phương thức f mới cho lớp cơ sở chỉ gọi _f. Sau đó, bạn tự do thay đổi f trong lớp con.

Tuy nhiên, nó có thể không được coi là thực hành tốt để thay đổi chữ ký phương thức trong lớp con.

class A(object): 
    def f(self, x): 
     return self._f(x) 

    # recursive method 
    def _f(self, x): 
     print x, 
     if x < 0: 
      self._f(x+1) 
     if x > 0: 
      self._f(x-1) 
     if x == 0: 
      print "" 

class B(A): 
    # Override method 
    def f(self): 
     # do some pretty cool stuff 
     super(B, self).f(25) 

if __name__ == "__main__": 
    A().f(5) 
    B().f() 
1

Trong ví dụ thứ hai của bạn, vấn đề của bạn là self bạn đang đi dọc theo là một thể hiện của B, không phải là một thể hiện của A, vì vậy khi bạn cố gắng để gọi self.f bạn đang gọi điện thoại B.f.

Thật không may, hành vi bạn đang xem thực sự là cách lập trình OO nên hoạt động. Bất cứ điều gì bạn làm để làm việc xung quanh điều này sẽ là một chút của một hack xung quanh mô hình OO. Một tùy chọn khác mà có thể có nhiều rõ ràng so với sử dụng mangling, nhưng không nhất thiết phải là "đệ quy thực", sẽ được vượt qua cùng các chức năng bạn muốn recurse trên:

class A(object): 
    # recursive method 
    def f(self, x, func=None): 

     if func is None: 
      func = A.f 

     print x, 

     if x < 0: 
      func(self,x+1,func) 
     if x > 0: 
      func(self,x-1,func) 
     if x == 0: 
      print "" 

class B(A): 
    # Override method 
    def f(self): 
     # do some pretty cool stuff 
     super(B, self).f(25) 

if __name__ == "__main__": 
    A().f(5) 
    B().f() 

Điều này có lẽ không phải là cách tốt nhất này có thể được viết, nhưng tôi nghĩ nó có ý tưởng trên. Bạn có thể luân phiên thử qua số A.f trong cuộc gọi của mình theo số B.f.

1

Nếu bạn không thể sửa đổi thực hiện A, bạn có thể tận dụng sự khác biệt về chữ ký chức năng.

class B(A): 
    def f(self, x=None): 
     if x is None: 
      # do some pretty cool stuff 
      self.f(25) 
     else: 
      super(B, self).f(x) 
+0

"nếu x = Không:" phải là "nếu x == Không:" hoặc vẫn tốt hơn "nếu x là Không:". – awatts

+0

@awatts: cố định nhưng nhận xét này quá ngắn. – SingleNegationElimination

Các vấn đề liên quan