2017-06-01 17 views
11

Có phải để ghi nhớ bản thân và nhóm của bạn để thực hiện chính xác lớp học không? Tôi không hoàn toàn được sử dụng một lớp trừu tượng như thế này:Khi nào nên sử dụng 'raise NotImplementedError'?

class RectangularRoom(object): 
    def __init__(self, width, height): 
     raise NotImplementedError 

    def cleanTileAtPosition(self, pos): 
     raise NotImplementedError 

    def isTileCleaned(self, m, n): 
     raise NotImplementedError 
+2

Quảng cáo chéo trang web: https://softwareengineering.stackexchange.com/q/231397/110531 – jonrsharpe

+1

Tôi sẽ nói: Khi nó đáp ứng ["Nguyên tắc ít ngạc nhiên nhất"] (https://en.wikipedia.org/wiki/Principle_of_least_astonishment). – MSeifert

Trả lời

15

Như các tài liệu khẳng định [docs],

Trong người dùng định nghĩa các lớp cơ sở, phương pháp trừu tượng nên nâng ngoại lệ này khi họ yêu cầu các lớp dẫn xuất để ghi đè lên phương thức, hoặc trong khi lớp đang được phát triển để chỉ ra rằng việc thực hiện thực sự vẫn cần phải được thêm vào.

Lưu ý rằng mặc dù chính trường hợp sử dụng nói lỗi này là dấu hiệu cho thấy các phương pháp trừu tượng đó phải được thực hiện trên lớp kế thừa, bạn có thể sử dụng nó tùy bạn muốn, như cho dấu hiệu của một dấu TODO.

+0

Đối với phương pháp trừu tượng, tôi thích sử dụng 'abc' (xem [câu trả lời của tôi] (https://stackoverflow.com/a/44316506/4653485)). –

0

Bạn có thể muốn bạn sử dụng @property trang trí,

>>> class Foo(): 
...  @property 
...  def todo(self): 
...    raise NotImplementedError("To be implemented") 
... 
>>> f = Foo() 
>>> f.todo 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in todo 
NotImplementedError: To be implemented 
+0

Tôi không thấy làm thế nào để giải quyết các câu hỏi, đó là * khi sử dụng nó *. – TemporalWolf

0

xem xét nếu thay vào đó là:

class RectangularRoom(object): 
    def __init__(self, width, height): 
     pass 

    def cleanTileAtPosition(self, pos): 
     pass 

    def isTileCleaned(self, m, n): 
     pass 

và bạn phân lớp và quên nói với nó như thế nào để isTileCleaned() hoặc, có lẽ nhiều khả năng , đánh máy là isTileCLeaned(). Sau đó, trong mã của bạn, bạn sẽ nhận được một None khi bạn gọi nó.

  • Bạn sẽ nhận được hàm bị ghi đè mà bạn muốn? Chắc chắn không phải.
  • Có phải là None kết quả hợp lệ không? Ai biết.
  • Hành vi đó có ý định không? Hầu như chắc chắn là không.
  • Bạn sẽ gặp lỗi? Nó phụ thuộc.

này lực lượng bạn thực hiện nó, vì nó sẽ ném một ngoại lệ cho đến khi bạn làm như vậy. Điều này loại bỏ rất nhiều lỗi im lặng. Nó tương tự như lý do tại sao một bare except is almost never a good idea: bởi vì mọi người phạm sai lầm và điều này làm cho chắc chắn rằng họ không được quét dưới tấm thảm.

3

Uriel says, nó có nghĩa là cho một phương thức trong lớp trừu tượng cần được triển khai trong lớp con, nhưng cũng có thể được sử dụng để biểu thị TODO.

Python 3 đi kèm với giải pháp thay thế cho trường hợp sử dụng đầu tiên: Abstract Base Classes. Những sự giúp đỡ tạo lớp trừu tượng:

class C(abc.ABC): 
    @abstractmethod 
    def my_abstract_method(self, ...): 
    ... 

Khi instantiating C, bạn sẽ nhận được một lỗi vì my_abstract_method là trừu tượng. Bạn cần phải thực hiện nó trong một lớp con.

TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method 

Phân lớp C và triển khai my_abstract_method.

class D(C): 
    def my_abstract_method(self, ...): 
    ... 

Bây giờ bạn có thể nhanh chóng D.

C.my_abstract_method không cần để trống. Nó có thể được gọi từ D sử dụng super().

Lợi thế của điều này hơn NotImplementedError là bạn nhận được rõ ràng Exception vào thời điểm khởi tạo, không phải lúc gọi phương thức.

+1

Có sẵn trong Python 2.6+. Chỉ cần 'từ abc nhập ABCMeta, abstractmethod' và xác định ABC của bạn với' __metaclass__ = ABCMeta'. Tài liệu: https://docs.python.org/2/library/abc.html – BoltzmannBrain

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