2011-01-25 35 views
5

Abstract base classes can still be handy in Python. Trong khi viết một lớp cơ sở trừu tượng mà tôi muốn mọi lớp con có, chẳng hạn, một phương pháp spam(), tôi muốn viết một cái gì đó như thế này:Python(), các lớp cơ sở trừu tượng, và NotImplementedError

class Abstract(object): 
    def spam(self): 
     raise NotImplementedError 

Thách thức này cũng muốn sử dụng super() và thực hiện nó đúng cách bằng cách đưa nó vào toàn bộ chuỗi lớp con. Trong trường hợp này, có vẻ như tôi phải quấn mỗi super cuộc gọi như sau:

class Useful(Abstract): 
    def spam(self): 
     try: 
      super(Useful, self).spam() 
     except NotImplementedError, e: 
      pass 
     print("It's okay.") 

Đó là okay cho một lớp con đơn giản, nhưng khi viết một lớp học có nhiều phương pháp, thử-trừ điều được một chút rườm rà và một chút xấu xí. Có cách nào tốt hơn để phân lớp từ các lớp cơ sở trừu tượng? Tôi chỉ làm điều đó sai?

+5

Điều đó làm cho rất ít ý nghĩa. Bạn nên biết các phương thức siêu lớp nào được triển khai (mà 'super' có ý nghĩa) và không được triển khai thực hiện bởi vì chúng trừu tượng. Bạn có thể đọc nguồn. –

+0

'nâng SyntaxError' cũng bằng ngôn ngữ. Câu hỏi đặt ra là "tại sao viết tất cả mã đó khi kiểm tra đơn giản của lớp trừu tượng có thể giúp bạn viết tất cả mã đó"? –

+0

@ S.Lott Ah, đã hiểu rồi. Bạn nên gửi nó như một câu trả lời, bằng cách này, bởi vì nó được. – gotgenes

Trả lời

8

Bạn có thể làm điều này sạch sẽ trong python 2.6+ với abc module:

import abc 
class B(object): 
    __metaclass__ = abc.ABCMeta 
    @abc.abstractmethod 
    def foo(self): 
     print 'In B' 

class C(B): 
    def foo(self): 
     super(C, self).foo() 
     print 'In C' 

C().foo() 

Sản lượng sẽ

In B 
In C 
+0

Điều này không nhất thiết phải giống nhau - người ta không thể khởi tạo B từ ví dụ của bạn. –

+0

Thú vị! Tôi thậm chí đã không bắt được sự bổ sung của mô-đun 'abc'! – gotgenes

+0

@Tomasz Cũng thú vị. Các hàm ý cho thử nghiệm đơn vị là gì, nếu không thể khởi tạo lớp? – gotgenes

7

Đừng viết tất cả những gì mã. Kiểm tra đơn giản của lớp trừu tượng có thể giúp bạn viết tất cả các mã đó.

Nếu phương pháp trừu tượng, lớp con cụ thể không gọi là siêu.

Nếu phương pháp là bê tông, lớp con cụ thể gọi là siêu.

+1

Đó là một giải pháp đơn giản trừ khi bạn đang đi cho một loại khác nhau của thừa kế hợp tác xã. I E. Tóm tắt là A. Một <- B, nhưng sau đó bạn muốn hỗ trợ chèn C như vậy A <- C <- B. B không gọi siêu nên nó không hoạt động đúng. Tôi nghĩ rằng điểm chính là khi bạn sử dụng siêu bạn nên nhận thức được thừa kế hợp tác và mục tiêu của bạn cho hệ thống phân cấp lớp cụ thể của bạn. Xem câu trả lời của tôi để thực hiện ví dụ của tôi ở trên. –

3

Điểm mấu chốt để hiểu điều này là super() là để triển khai kế thừa hợp tác xã. Làm thế nào các lớp học hợp tác là vào bạn lập trình viên. super() không phải là ma thuật và không biết chính xác những gì bạn muốn! Không có nhiều điểm trong việc sử dụng siêu cho một hệ thống phân cấp phẳng mà không cần thừa kế hợp tác, vì vậy trong trường hợp đó đề xuất của S. Lott là điểm trên. Lớp con của tháng hữu ích hoặc có thể không muốn sử dụng super() tùy mục tiêu của họ :)

Ví dụ: Tóm tắt là A. Một < - B, nhưng sau đó bạn muốn hỗ trợ chèn của C như vậy Một < - C < - B .

class A(object):                       
    """I am an abstract abstraction :)""" 
    def foo(self): 
     raise NotImplementedError('I need to be implemented!') 

class B(A): 
    """I want to implement A""" 
    def foo(self): 
     print('B: foo') 
     # MRO Stops here, unless super is not A 
     position = self.__class__.__mro__.index 
     if not position(B) + 1 == position(A): 
      super().foo() 

b = B()  
b.foo() 

class C(A): 
    """I want to modify B and all its siblings (see below)""" 
    def foo(self): 
     print('C: foo') 
     # MRO Stops here, unless super is not A 
     position = self.__class__.__mro__.index 
     if not position(C) + 1 == position(A): 
      super().foo() 

print('') 
print('B: Old __base__ and __mro__:\n') 
print('Base:', B.__bases__) 
print('MRO:', B.__mro__) 
print('') 
# __mro__ change implementation 
B.__bases__ = (C,) 
print('B: New __base__ and __mro__:\n') 
print('Base:', B.__bases__) 
print('MRO:', B.__mro__) 
print('') 
b.foo() 

Và kết quả:

B: foo 

B: Old __base__ and __mro__: 

Base: (<class '__main__.A'>,) 
MRO: (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>) 

B: New __base__ and __mro__: 

Base: (<class '__main__.C'>,) 
MRO: (<class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) 

B: foo 
C: foo 
Các vấn đề liên quan