本篇文章主要介紹面向?qū)ο缶幊獭?/p>
面向?qū)ο缶幊?/h4>
幾個定義
- 面向過程編程:圍繞函數(shù)塑荒,編寫能處理數(shù)據(jù)的代碼塊的編程方式撇吞。
- 類、對象:面向?qū)ο缶幊痰膬蓚€主要方面梨水。一個類(Class)能創(chuàng)建一種新的類型老客;對象(Object)是類的實例僚饭。可這樣類比:你可擁有類型 int 的變量胧砰,也即鳍鸵,存儲整數(shù)的變量是 int類 的對象實例。
- 字段尉间、方法和屬性:從屬于對象或類的變量叫字段(Field)偿乖;對象調(diào)用從屬于類的函數(shù)實現(xiàn)某些功能,這些函數(shù)叫類的方法(Method)乌妒;字段和方法統(tǒng)稱為累的屬性(Attribute)汹想。
Tips: 不同于靜態(tài)語言外邓,Python 中即使是整數(shù)也會被視為對象(int類的對象)撤蚊,同 Java 中裝箱與拆箱概念頗為相似。
類和對象
最簡單的類結(jié)構(gòu)如下所示:
class Student(object):
pass # 一個空的代碼塊
# 創(chuàng)建類對象實例
student = Student()
print(student)
# 打铀鸹啊:<__main__.Student object at 0x101985f28>
*Tips: *
- Python 中所有類均繼承自 object侦啸;
- Python 打印對象槽唾,默認可查看對象地址。Python 會在它找到的任何空間來存儲對象光涂。
類屬性和實例屬性
方法(Method)
Python 對比于 Java 類方法屬性庞萍,有兩個特殊點:
- 類中定義的所有方法,第一個參數(shù)必須是 self忘闻;相當于 Java 中的 this 引用钝计;
- _init_() 方法:在類的對象被實例化時立即運行;相當于 Java 中的構(gòu)造方法齐佳。
Tips: Python中不存在方法的重載私恬,方法的重載是對同一個方法使用可變參數(shù)來實現(xiàn),這在后面函數(shù)參數(shù)這塊會提到炼吴。
示例代碼如下:
class Student(object):
count = 0 # 類變量
def __init__(self, name):
self.name = name # 實例變量
def say_hi(self):
print(r'Hello, I'm', self.name)
student = Student('Coral')
student.say_hi()
# 打颖久:Hello, I'm Coral
字段(Field)
Python 中字段有兩種類型——類變量與對象變量,對比上述示例代碼硅蹦,兩者的區(qū)別點如下圖所示:
因為 Python 是動態(tài)語言荣德,可以給類創(chuàng)建的實例動態(tài)綁定屬性,那么如何給 實例 綁定屬性童芹?如何給 類 綁定屬性呢涮瞻?
1)給實例綁定屬性
- 通過在 _init_ 方法中給 self 綁定屬性饲宛,這種屬性所有對象實例均可訪問;
- 直接給實例綁定嗜价,這種屬性只適用于該實例,其他實例不能訪問該屬性久锥。如:
student = Student('Coral')
# grade是給實例動態(tài)綁定的屬性,name是通過 self綁定的屬性
student.grade = 90
print('{} grade = {} '.format(student.name, student.grade))
student2 = Student('Jane')
print(student2.grade)
# 這句會拋出:AttributeError: 'Student' object has no attribute 'grade'
2)給類綁定屬性
要讓同一個字段屬性對所有實例均適用瑟由,除了 self 綁定,還可以適用 類屬性歹苦。
- 類屬性,直接在 class 中定義屬性殴瘦,歸整個 Student 類所有狠角,如 count 字段。
Tips: 當 實例屬性 和 類屬性 同名時蚪腋,實例屬性 優(yōu)于 類屬性丰歌,也即姨蟋,實力屬性會覆蓋類屬性,所以在項目中要避免使用這種同名變量立帖。
訪問限制
Java 中有四種訪問修飾符眼溶,Python 中并沒有指定具體的訪問修飾符,僅是按照一種約定的寫法來晓勇,如下圖所示:
獲取對象信息
在 Java 中通常會判斷一個對象是什么類型堂飞,用 instanceOf 來判斷,Python 中也有判斷對象類型的方法绑咱,還可以獲取對象擁有的屬性和方法酝静,這些都是 Python 內(nèi)置的方法。常見的如下圖所示:
這里重點說下 isinstance() 方法羡玛,示例如下:
a = list() # a 是 list 類型
b = Animal() # b 是 Animal 類型
c = Dog() # c 是 Dog 類型
# 1.判斷一個變量是否是某個類型可以用 isinstance() 判斷:
print('a is list:', isinstance(a, list)) # True
print('b is Animal:', isinstance(b, Animal)) # True
print('c is Dog:', isinstance(c, Dog)) # True
print('c is Animal:', isinstance(c, Animal)) # True
# 2. 能用 type() 判斷的基本類型也可以用 isinstance() 判斷:
print(isinstance('a', str)) # True
print(isinstance(123, int)) # True
print(isinstance(b'a', bytes)) # True
# 3. 另外别智,isinstance() 還可以判斷一個變量是否是某些類型中的一種:
# 判斷變量是否是 list 或 tuple.
def is_list_or_tuple(x):
return isinstance(x, (list, tuple))
Tips: 區(qū)別于 type,對于 class 繼承關(guān)系稼稿,不便使用 type();要判斷 class 類型薄榛,使用 isinstance() 函數(shù)。因為 type() 只能返回對象本身的類型让歼,比如 type(dog) != type(animal)敞恋, 但是 isinstance(dog, Dog) = isinstance(dog, Animal)。
繼承和多態(tài)
Python 中允許多繼承谋右,沒有接口實現(xiàn)的概念硬猫。繼承和多態(tài)總結(jié)點如下:
Python 中沒有方法的重載,但是存在方法的覆蓋改执,子類可以覆蓋父類方法啸蜜,也適用于運行時綁定傳入的實例。
關(guān)于繼承的幾個問題
- 子類 能否繼承 父類綁定的 屬性辈挂?(每個類通過 self 或者 給實例動態(tài)綁定的 屬性都是該類實例 獨立擁有衬横,跟子類沒有任何關(guān)聯(lián)?)
A: 子類不能繼承 父類中通過 self或者 動態(tài)綁定的屬性终蒂; - 子類 是否只能繼承 父類綁定的 類屬性蜂林?
A:子類能繼承 父類中的 類屬性,在操作該類屬性時拇泣,使用 ChildClass.property 訪問該類屬性噪叙; - 子類可以繼承 父類的所有方法?
A:Python 中方法沒有 訪問限制符修飾霉翔; - 每個類通過 self 或者 給實例動態(tài)綁定的 屬性都是該類實例 獨立擁有睁蕾,跟子類沒有任何關(guān)聯(lián)?
A:是早龟。 - 子類和父類有同名的 屬性惫霸,優(yōu)先使用哪個壹店?(避免這種情況芝加,直接繼承使用父類的屬性)
A:子類優(yōu)先,但最好不要讓子類屬性和父類屬性同名 将塑。 - 子類能否繼承父類中 __xxx 隱藏屬性蝌麸?
A:這個可以看做是每個類通過 self 綁定的屬性均屬于本類所有来吩,父類中通過 self 綁定的屬性不管是否是隱藏屬性,子類直接訪問就會拋出:AttributeError: 'Dog' object has no attribute '_BaseClass__name' .