2014-10-20 23 views
9

Tôi có thể đến từ một tư duy khác, chủ yếu là lập trình viên C++. Câu hỏi này phải làm với OOP trong Python và cụ thể hơn là các phương thức ảo thuần túy. Vì vậy, lấy mã tôi thích nghi từ this question Tôi đang xem xét mẫu cơ bản này.Có phải chức năng ảo thuần túy của Python có thể và/hoặc đáng giá không?

class Animal(): 
    def speak(self): 
     print("...") 

class Cat(Animal): 
    def speak(self): 
     print("meow") 

class Dog(Animal): 
    def speak(self): 
     print("woof") 

my_pets = [Dog(), Cat(), Dog()] 

for _pet in my_pets: 
    _pet.speak() 

Vì vậy, bạn thấy nó gọi hàm nói cho các lớp có nguồn gốc khác nhau. Bây giờ vấn đề của tôi là gõ vịt là tất cả tốt và tôi nghĩ rằng tôi đã nắm bắt nó. Tuy nhiên, có sai khi theo đuổi OOP nghiêm ngặt hơn trong Python không? Vì vậy, tôi đã xem số Abstract Base Classes và cụ thể là abstractmethod. Với tôi tất cả điều này dường như làm là cho phép tôi gọi phương thức lớp cơ sở với siêu. Có cách nào/lý do (trong Python) để làm cho speak() tinh khiết như vậy mà thực hiện một động vật có nguồn gốc mà không nói sẽ ném một lỗi?

Đối số của tôi cho việc theo đuổi như vậy sẽ là khi viết mô-đun và khung mà bạn dự định mọi người phân lớp, điều này sẽ tự tài liệu cho họ thực tế là họ cần triển khai hàm. Một ý tưởng có lẽ rất xấu là một cái gì đó như thế này, có lớp cơ sở "tinh khiết" chức năng ném một ngoại lệ. Vấn đề là lỗi này được tìm thấy trong thời gian chạy!

class VirtualException(BaseException): 
    def __init__(self, _type, _func): 
     BaseException(self) 

class Animal(): 
    def speak(self): 
     raise VirtualException() 

class Cat(Animal): 
    def speak(self): 
     print("meow") 

class Dog(Animal): 
    def speak(self): 
     print("woof") 

class Wildebeest(Animal): 
    def function2(self): 
     print("What!") 

my_pets = [Dog(), Cat(), Dog(), Wildebeest()] 

for _pet in my_pets: 
    _pet.speak() 
+1

Theo tôi thấy, những gì bạn mô tả chính xác là những gì 'abstractmethod' thực hiện. Bạn có thể làm rõ những gì bạn muốn 'abstractmethod' không cung cấp? Bạn sẽ không nhận được một giải pháp "biên dịch-thời gian" cho bất cứ điều gì, bởi vì Python không thực sự có một thời gian biên dịch theo nghĩa C++. Nhưng 'abstractmethod' cho phép bạn nhận được lỗi khi lớp được định nghĩa (trước khi nó được khởi tạo). – BrenBarn

+0

@BrenBarn Xin lỗi vì tuyên bố vụng về. Tôi biết tôi sẽ không nhận được lỗi thời gian biên dịch. Nó chỉ là tốt đẹp để biết tôi có thể nhận được một lỗi khi đối tượng lớp cơ sở trừu tượng hoặc một đối tượng lớp dẫn xuất không hợp lệ được khởi tạo. Lỗi của tôi là sử dụng một trình thông dịch Python 3 làm abstractmethod xuất hiện để không làm gì cả vì tôi không định nghĩa lớp theo cách Python3 đúng. Xem câu trả lời được chấp nhận. – benzeno

+0

Related: http://stackoverflow.com/questions/4714136/python-how-to-implement-virtual-methods/38717503 –

Trả lời

15

lớp cơ sở trừu tượng đã làm những gì bạn muốn. abstractmethod không liên quan gì đến việc bạn gọi phương thức với super; bạn có thể làm điều đó anyway. Thay vào đó, bất kỳ phương pháp nào được trang trí với abstractmethod phải được ghi đè để một lớp con có thể được hiển thị tức thì:

>>> class Foo(object): 
...  __metaclass__ = abc.ABCMeta 
...  @abc.abstractmethod 
...  def foo(self): pass 
... 
>>> class Bar(Foo): pass 
... 
>>> class Baz(Bar): 
...  def foo(self): return super(Baz, self).foo() 
... 
>>> Foo() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: Can't instantiate abstract class Foo with abstract methods foo 
>>> Bar() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: Can't instantiate abstract class Bar with abstract methods foo 
>>> Baz() 
<__main__.Baz object at 0x0000000001EC10B8> 
+0

Ok đây là những gì tôi đang tìm kiếm. Sai lầm của tôi đã nghĩ rằng Python2 và 3 không phải là cực kỳ khác nhau. Tôi có lẽ đã nhầm lẫn câu hỏi này nhưng Python 3 chỉ cho phép điều này chạy mà không cần nâng cao bất cứ điều gì. Trừ khi bạn gọi 'class Foo (metaclass = ABCMeta):'. Sau đó tôi hiểu lầm abstractmethod là vì các tài liệu Python2 nhận xét về siêu và tôi không thể nhìn thấy nếu nó đã làm bất cứ điều gì khác. Cảm ơn. – benzeno

6

Vấn đề là lỗi này được tìm thấy trong thời gian chạy!

Vâng, đó là Python ... hầu hết các lỗi sẽ hiển thị khi chạy.

Theo như tôi biết, mô hình phổ biến nhất để đối phó với là bằng Python là cơ bản những gì bạn mô tả: chỉ cần có phương pháp speak các lớp cơ sở của ném một ngoại lệ:

class Animal(): 
    def speak(self): 
     raise NotImplementedError('You need to define a speak method!') 
+2

+1 cho "hầu hết các lỗi sẽ hiển thị khi chạy"! –

+0

Được rồi ... xin lỗi đó là vụng về. Tôi chưa bao giờ nghĩ khác. Tôi đã chỉ hy vọng cho thứ hai tốt nhất, vì vậy khi một đối tượng được instantiated như trái ngược với sau này khi thực hiện một cuộc gọi để nói chuyện. – benzeno

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