接下來算是小聊一下 Python 的 Class 語法而已,算是稍微休息一下,所以這邊簡單聊就好。
Python 本身就是一個物件導向語言(Object-oriented programming,就是俗稱的 OOP),那麼什麼是物件導向呢?JavaScript 也是物件導向語言嗎?
好吧,這個問題其實困擾我很久,所以前面就稍微簡單聊一下這個東西,畢竟有些人說 JavaScript 是物件導向語言也有人家說 JavaScript 不是物件導向的語言,那麼到底什麼是物件導向呢?與其繞口令不如翻一些文件來說明,先讓我們看一下維基百科對於「物件導向程式設計」的解釋是什麼:
它可能包含資料、特性、程式碼與方法。物件則指的是類別(class)的實例。它將物件作為程式的基本單元,將程式和資料封裝其中,以提高軟體的重用性、靈活性和擴充性,物件裡的程式可以存取及經常修改物件相關連的資料。在物件導向程式程式設計裡,電腦程式會被設計成彼此相關的物件。
相信這邊你應該看得非常混淆,畢竟描述的很文鄒鄒:
但是你可能會想說「物件導向,那這個是不是跟物件有關係啊?」
答案是「沒錯,確實有關係」,就是與物件有很大的關聯性,除此之外通常物件導向的開發會是以一個類別去做宣告,也就是 class
,而這個 class
通常是一個抽象的物件,舉例來講會有一個狗的類別,然這個狗的類別會具有牠所有的基本特徵,所以寫法可能是這樣:
class 狗
public 方法:
吼叫()
指甲:
private 方法:
毛色:
品種:
尾巴長度:
名字:
學名:
(我絕對不會說我是看著我家的狗在想上面的 class)
而我們可以透過上面的狗類別一直繼承下來給予其他特有的名稱,例如:毛色是棕色、品種是米克斯、尾巴無等等,所以你可以把物件導向也想像成它是一個藍圖概念。
依照上面的說法來講,所以 JavaScript 也是物件導向語言囉?答案基本上是的,JavaScript 確實也是物件導向語言,但是 JavaScript 是以 原型基礎為導向 的物件導向語言,我相信你看到這邊已經感覺像是繞口令了,所以接下來就來看一些範例好了。
以下是 Java 語言,我隨便簡單寫出來參考比較而已:
class Home
{
public String father;
public String mother;
Home(String a, String b) {
father = a;
mother = b;
}
public void myFather(){
System.out.println("my father is " + father);
}
}
public class main
{
public static void main(String[] args)
{
Home myHome = new Home("jack", "judy");
System.out.println(myHome.father); // jack
System.out.println(myHome.mother); // mother
myHome.myFather(); // my father is jack
}
}
但是如果將上面程式碼改寫成 JavaScript 的話則是以下:
function Home(father, mother) {
this.father = father;
this.mother = mother;
}
Home.prototype.myFather = function() {
console.log('my father is ' + this.father);
}
const myHome = new Home('Jack', 'Judy');
console.log(myHome.father, myHome.mother);// Jack Judy
myHome.myFather(); // my father is jack
至於為什麼挑 Java 當作範例就不多說明了(笑)。
基本上我們可以看到 Java 就是以 class
去抽象化一個東西、一個概念,而這個 class
可以一直被繼承。
但是前面範例中我們也有看到 JavaScript 也可以做到類似的事情,難道這樣子 JavaScript 還不算是一個物件導向語言嗎?事實上 JavaScript 不太適合直接說它是 OOP,而是比較適合叫 OOJS(Object-oriented JavaScript),畢竟 JavaScript 是以原型為基礎的語言,詳情可以在閱讀 MDN 文件中的 初學者應知道的物件導向 JavaScript 章節會有更好的描述,而前面這邊只是小小的簡單聊一下而已,並沒有打算過度深入談論這一塊。
oh!題外話一下,雖然 JavaScript 在 ECMAScript6 引入了 class
語法,但本質上那只是 prototype
的語法糖而已,實際上 JavaScript 在底層的運作依然是屬於原型,千萬不要被 JavaScript 的 class
語法糖給騙了唷~
前面有提到 Python 本身就是一個 OOP 語言也有講到什麼是物件導向的概念之後,接下來我們也要來認識一下 Python 要如何建立屬於自己的 class
,有寫過 JavaScript class
語法的人基本上會感覺很熟悉或者格外親切,因為語法上的使用非常的雷同:
class Home:
father = 'jack'
這邊我們也可以簡單看一下 JavaScript 的 class
:
class Home {
father = 'jack'
}
是不是覺得兩者相似度很高呢?感到格外親切了呢?
那麼 Python 該如何實例化剛剛宣告的 class 呢?你不知道什麼是實例化嗎?簡單來講你可以把它當作你給了這個抽象的東西一個生命的概念,所以讓我們來看一下怎麼該實例化:
class Home:
father = 'jack'
myHome = Home()
print(myHome.father) # jack
有沒有覺得超級簡單呢?連 new
都省略了呢!是不是覺得超級簡潔呢?(JavaScript 必須使用 new
才可以。)
但是這時候你可以會想說建立一個 class
的時候,我們都會需要傳入一些參數告知目前 class
的一些初始值或者樣貌,以狗來舉例的話,你給予狗生命時總要給牠毛色與品種吧?
那麼以 JavaScript 的寫法來講的話就會像這樣:
class Home {
constructor(father) {
this.father = father;
}
}
const myHome = new Home('jack');
console.log(myHome.father); // jack
那麼 Python 呢?Python 也是用 constructor
嗎?Python 主要是用 __init__
函式,所有的 class
都會有一個 __init__
,就跟 JavaScript 一樣,所有的 class
都有一個 constructor
可以使用,所以寫法就會變成以下:
class Home:
def __init__ (self, father):
self.father = father
myHome = Home('jack')
print(myHome.father) # jack
此刻的你應該會覺得很疑惑 __init__
中的 self
是什麼東西?你可以把它想像成 JavaScript 中 constructor
的 this
,但是千萬不要把 Python 中的 self
跟 JavaScript 的 self
搞混,剛好前陣子我有寫一篇關於 JavaScript 的 self
是什麼的文章,也推薦給你參考看看。
好,拉回 Python 中,所以 Python 的 self
會指向 class Home
本身,而每次建立一個 class
的時候,Python 都會自動呼叫 __init__
函式(JavaScript 也是相同的,它會自動呼叫 constructor
函式)基本上你也不一定要宣告為 self
你也可以叫別的,例如:hello
or ray
等等:
class Home:
def __init__ (ray, father):
ray.father = father
myHome = Home('jack')
print(myHome.father) # jack
但是我建議還是保留叫 self
會比較好,如果你取名一個很奇怪的名字,可能會被約出去喝咖啡。
那麼接下來也是與 Java 類似,我們會將函式方法寫在 class
中,但是這邊要注意,請記得替該方法傳入 self
,否則你會無法呼叫 class
本身的屬性:
class Home:
def __init__ (self, father):
self.father = father
def myFather(self):
print('my father is ' + self.father)
myHome = Home('jack')
print(myHome.father) # jack
myHome.myFather() # my father is jack
當如果你想修改 Home 中的屬性的話,也非常的簡單,就跟修改物件屬性的方式相同:
class Home:
def __init__ (self, father):
self.father = father
def myFather(self):
print('my father is ' + self.father)
myHome = Home('jack')
print(myHome.father) # jack
myHome.myFather() # my father is jack
myHome.father = 'Ray'
print(myHome.father) # Ray
其他的還有刪除 class 中的屬性與方法等等:
class Home:
def __init__ (self, father):
self.father = father
def myFather(self):
print('my father is ' + self.father)
myHome = Home('jack')
print(myHome.father) # jack
myHome.myFather() # my father is jack
myHome.father = 'Ray'
print(myHome.father) # Ray
del myHome.father
del myHome
但是這邊要注意,當刪除了之後就無法再被呼叫囉。
最後一種寫法是比較特別的狀況,通常來講 class
內容是不能為空的,如果是特殊狀況而需要寫一個空的 class
是可以使用 pass
語法來避免出錯:
class Home:
pass
否則正常來講你可能會得到「IndentationError: expected an indented block
」這個錯誤。
那麼這一章節都已經提到 class
,那麼下一章節就閃不掉所謂的繼承啦~
最近 Mac 好像在發神經一樣,莫名其妙就會準備飛機起飛,難道...它在暗示我該換 M1 了嗎 QQ?