面向對象的設計中,抽象類,接口這些必不可少的東西,在python中是如何提現的呢?
python作為一個動態語言,沒有強類型的檢查,而是以鴨子類型的方式提現,在執行的時候python不嚴格要求你必須是繼承指定的父類而來,只要在調用的時候你有相應的方法和屬性就可以了,長的像鴨子你就是鴨子。
也正是基於python這樣的特性,python中沒有interface的概念,有說interface並不是普遍存在的,而是作為一個特例出現在java中,為的是解決多繼承的問題。python支持多繼承,自然沒有這個需要了。然而我們難免會有這樣的需求:子類必須實現某些指定的方法和屬性,否則就拋異常。使用一些笨方法自然是可以達到相同的效果,但是python為我們提供了abc模塊。
http://bbs.chinaunix.net/thread-771123-1-1.html
java中的抽象類是為了實現c++中的抽象類和模板之類的東西
接口是為了解決java不能多繼承的問題很顯然樓主是從java才開始接觸面向對象程序設計的。實際上java的“接口”是一個特例而非普通現象。如果可以多繼承的話,那還要接口干什么?
實際上python才是最符合現實邏輯的“面向對象”
python允許多繼承,正如現實中,你既是公民也是納稅人,我們直接使用這些“類”而不需要特別的創建什么“納稅人接口”
python中所有的類,都是抽象類,或者說根本不存在抽象類,類方法可以直接使用,“類”本身在定義的時候就已經實例化,你可以通過輸入:某類[回車]看到其內存句柄。這是符合事實的,並且時簡約明了的。
而在C++和java當中,一個類定義了以后,肯定是占用了內存空間,但是同時他又沒有實例化,如果要使用的話還得實例化一次,又要占用一些內存空間。而類定義所占用的內存空間,使用率很低。
python中不存在“基類”的概念,也沒有單根,更沒有基本類型,所有的一切都是對象。
python是無神論的最完美體現,沒有亞當,沒有上帝,沒有鬼神,沒有唯一的主。你愛信什么信什么,愛是什么是什么,沒有任何約束,但是不能存在特殊。另外,python根本沒有意去模仿java的接口,因為那完全沒必要,python的標准類就完全包含java中的接口的所有功能。倒是模仿一下c++的模板會有些實際用途。
好了,說完抽象類,接口的來歷,我們看一看python中的abc模塊是如何玩兒的:
python-3.6.0-docs-html/library/abc.html?highlight=abc#module-abc
https://www.python.org/dev/peps/pep-3119/
from abc import ABCMeta, abstractmethod, abstractproperty
class Drawable(metaclass=ABCMeta):
"""docstring for Drawable"""
@abstractproperty
def size(self):
# return 'mysize'
pass
@abstractmethod
def draw(self, x, y, scale=1.0):
# print(x * scale, y * scale)
pass
def double_draw(self, x, y):
self.draw(x, y, scale=2.0)
class Cicle(Drawable):
# 1. 使用繼承的方法
"""docstring for Cicle"""
def draw(self, x, y, scale=1.0):
print(x * scale, y * scale)
@property
def size(self):
return 'Cicle size'
# Cicle如果沒有override draw函數和size 屬性,那么實例化的時候就會報錯
# TypeError: Can't instantiate abstract class Cicle with abstract methods draw, size
c = Cicle()
print(dir(c))
c.draw(1, 2)
c.double_draw(1, 2)
print(isinstance(c, Drawable)) # True
print(isinstance(c, Drawable)) # True
class Rectangle():
"""docstring for Cicle"""
pass
# 使用抽象類函數的register方法注冊具體的class
# 通過注冊的類,可以直接實例化,但是無法訪問抽象類的所有成員
# 其實就是只是讓isinstance、issubclass識別注冊的類為抽象類的成員和實例
Drawable.register(Rectangle)
r = Rectangle()
# r.double_draw(1, 2)
# AttributeError: 'Rectangle' object has no attribute 'double_draw'
print(dir(r))
print(isinstance(r, Drawable)) # True
print(issubclass(Rectangle, Drawable)) # True
# ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', 'double_draw', 'draw', 'size']
# 1.0 2.0
# 2.0 4.0
# True
# True
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
# True
# True
# [Finished in 0.2s]