你們好,做爲小白,最近學習了不少Python OOP編程的知識,由於腦容量有限,特此一一按照學習順序記錄下來,若是哪裏有錯誤,還請大神儘快指出,以避免誤導他人。。。java
首先讓咱們簡單瞭解一下何爲面向對象編程:python
把一組數據結構和處理它們的方法組成對象(object),把相同行爲的對象概括爲類(class),經過類的封裝(encapsulation)隱藏內部細節,經過繼承(inheritance)實現類的特化(specialization)和泛化(generalization),經過多態(polymorphism)實現基於對象類型的動態分派。
這樣一說貌似有些複雜,簡單來看的話能夠參考下面的解釋:c++
概念 | 解釋 |
---|---|
類(Class) | 用來描述具備相同的屬性和方法的對象的集合。它定義了該集合中每一個對象所共有的屬性和方法。對象是類的實例 |
類變量 | 類變量在整個實例化的對象中是公用的。類變量定義在類中且在函數體以外。類變量一般不做爲實例變量使用 |
數據成員 | 類變量或者實例變量, 用於處理類及其實例對象的相關的數據 |
方法重寫 | 若是從父類繼承的方法不能知足子類的需求,能夠對其進行改寫,這個過程叫方法的覆蓋(override),也稱爲方法的重寫 |
局部變量 | 定義在方法中的變量,只做用於當前實例的類 |
實例變量 | 在類的聲明中,屬性是用變量來表示的。這種變量就稱爲實例變量,是在類聲明的內部可是在類的其餘成員方法以外聲明的 |
繼承 | 即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也容許把一個派生類的對象做爲一個基類對象對待。例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關係(例圖,Dog是一個Animal) |
實例化 | 建立一個類的實例,類的具體對象 |
方法 | 類中定義的函數 |
對象 | 經過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法 |
下面讓咱們簡單定義一個汽車類:git
class Car: def __init__(self, color, model, year): self.color = color self.model = model self.year = year
這裏咱們建立了一個汽車類Car,它有三個公共屬性,分別是color(顏色),model(型號),year(生產年份)github
如今讓咱們新建一個對象my_car:編程
my_car = Car("yellow", "beetle", 1967)
查看一下my_car的屬性數據結構
print(f" My {my_car.color} car {my_car.model} is made in {my_car.year}") # My yellow car beetle is made in 1967
咱們想要給my_car添加一個新屬性wheelsssh
my_car.wheels = 5 print(f"Wheels: {my_car.wheels}") # Wheels: 5
使用dir(my_car)可讓咱們確認一下屬性是否存在:ide
dir(my_car) Out: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'color', 'model', 'wheels', <====已經添加成功啦 'year']
在Python中,咱們在類外聲明一個類變量,下面讓咱們修改一下Car類:函數
class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year
這樣的話,咱們在調用wheels這個變量時,能夠經過實例,或者直接調用Car.wheels:
my_car = Car("yellow", "beetle", 1967) print(f"My car is {my_car.color}") print(f"It has {Car.wheels} wheels") print(f"It has {my_car.wheels} wheels") Out: My car is yellow It has 0 wheels It has 0 wheels
這裏須要注意一下,若是想要經過my_car.wheels =xxx來修改wheels的值,不會真正修改類變量wheels的值,咱們來看一個具體的例子:
my_car = Car("yellow", "Beetle", "1966") my_other_car = Car("red", "corvette", "1999") print(f"My car is {my_car.color}") print(f"It has {my_car.wheels} wheels") print(f"My other car is {my_other_car.color}") print(f"It has {my_other_car.wheels} wheels") Out: My car is yellow It has 0 wheels My other car is red It has 0 wheels
咱們首先建立兩個實例my_car 和my_other_car ,默認的wheels=0,下面咱們首先直接經過Car這個類來修改類變量的值:
# Change the class variable value Car.wheels = 4 print(f"My car has {my_car.wheels} wheels") print(f"My other car has {my_other_car.wheels} wheels") Out: My car has 4 wheels My other car has 4 wheels
能夠看到這樣修改的話,Car類擁有的全部實例中的wheels值會被所有修改,若是咱們經過my_other_car 來修改呢?
# Change the instance variable value for my_car my_car.wheels = 5 print(f"My car has {my_car.wheels} wheels") print(f"My other car has {my_other_car.wheels} wheels") Out: My car has 5 wheels My other car has 4 wheels
如今你們能夠發現區別了,僅僅是修改了my_car中wheels的值,對類自己不會形成影響
在Python中的全部屬性都是public,可能有c++和java的同窗以爲神奇,其實python最初規定了一種特殊的命名方式來區分public仍是private,那就是下劃線_
我仍是拿同樣的例子說明:
class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year self._cupholders = 6 my_car = Car("yellow", "Beetle", "1969") print(f"It was built in {my_car.year}") Out: It was built in 1969
這裏Car類中的杯託 _cupholders就是「私有「屬性,爲何我這裏加上了引號,是由於Python只是名義上規定這種寫法,可是在實際訪問上沒啥卵用,依然能夠直接用._cupholders來訪問:
my_car.year = 1966 print(f"It was built in {my_car.year}") print(f"It has {my_car._cupholders} cupholders.") Out: It was built in 1966 It has 6 cupholders.
後來Python決定使用雙下劃線__來替換單下劃線,這樣能夠最大程度避免「意外訪問「,然而仍是沒有卵用,再來展現一下新方案:
class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year self.__cupholders = 6
其實某種程度上,這回效果仍是很明顯的,若是咱們還像剛纔同樣嘗試調用my_car.cupholders 會報錯:
my_car = Car("yellow", "Beetle", "1969") print(f"It was built in {my_car.year}") print(f"It has {my_car.__cupholders} cupholders.") Out: It was built in 1969 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-108-1efe56f0c054> in <module> 1 my_car = Car("yellow", "Beetle", "1969") 2 print(f"It was built in {my_car.year}") ----> 3 print(f"It has {my_car.__cupholders} cupholders.") AttributeError: 'Car' object has no attribute '__cupholders'
這個錯誤頗有意思,爲何會說cupholders這個變量不存在呢 ? 由於當Python看到__ 時,會自動在cupholders前面補上一個下劃線_和所屬類名,也就是說,這裏咱們嘗試用my_car.__cupholders 來調用時,Python默認的正確寫法是
my_car._Car__cupholders,如今再試一下:
print(f"It has {my_car._Car__cupholders} cupholders") Out: It has 6 cupholders
看見沒,依然沒攔住。。。。
不過我我的認爲這種規定公有私有變量的方式也是好處多多,這裏就仁者見仁,智者見智了~
就像剛剛提到的,Python全部的東西都是公有的,咱們能夠隨意的新增,修改,甚至刪除變量:
my_car = Car("yellow", "beetle", 1969) print(f"My car was built in {my_car.year}") my_car.year = 2003 print(f"It was built in {my_car.year}") del my_car.year print(f"It was built in {my_car.year}") Out: My car was built in 1969 It was built in 2003 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-110-46914b0bae82> in <module> 6 7 del my_car.year ----> 8 print(f"It was built in {my_car.year}") AttributeError: 'Car' object has no attribute 'year'
那咱們如何才能控制屬性的訪問權限呢?Python給出的答案是裝飾器 @property,這個相似於Java中的setter和getter,如今咱們試試:
class Car: def __init__(self, color, model, year): self.color = color self.model = model self.year = year self._voltage = 12 @property def voltage(self): return self._voltage @voltage.setter def voltage(self, volts): print("Warning: this can cause problems!") self._voltage = volts @voltage.deleter def voltage(self): print("Warning: the radio will stop working!") del self._voltage
咱們新增了voltage(電壓)這個屬性,並用property來控制外部的訪問權限,這裏咱們定義了三個方法,利用setter方法能夠改變voltage的值,利用getter方法來訪問,利用deleter方法實現刪除,接下來讓咱們新建實例來看看propert是如何工做的:
my_car = Car("yellow", "beetle", 1969) print(f"My car uses {my_car.voltage} volts") my_car.voltage = 6 print(f"My car now uses {my_car.voltage} volts") del my_car.voltage Out: My car uses 12 volts Warning: this can cause problems! My car now uses 6 volts Warning: the radio will stop working!
能夠發現,咱們這裏直接使用.voltage 而不是._voltage,這樣就告訴python去使用property裝飾的方法,咱們能夠經過使用@.setter and @.deleter 使屬性變爲read-only(只讀),從而保護voltage不會被隨意修改和刪除
今天主要總結了OOP編程中的類,對象,屬性,公有私有屬性,訪問權限這些基礎概念,下一篇文章會進一步深刻,若是本文有哪些語言使用不當,但願你們能夠指出,讓咱們一塊兒進步!
我以前的一些文章已經放到了Github上,若是感興趣的朋友能夠去看看,連接以下: