前言
前兩天一位小夥伴問了這樣乙個問題:雖然已經使用python一年多了,也用python寫過很多指令碼,**量從幾十行到上千行的也有,但從未使用過類(class),似乎用函式(def)就能解決所有問題,使用類有什麼好處?我什麼時候該用類呢?
關於這個問題,算是困惑了許多剛接觸python的同學,那麼本文就嘗試從多個角度來解讀這個問題。首先還是先來看看官方給出類與函式的解釋。
類提供了一種組合資料和功能的方法。 建立乙個新類意味著建立乙個新的物件型別,從而允許建立乙個該型別的新例項 。 每個類的例項可以擁有儲存自己狀態的屬性。 乙個類的例項也可以有改變自己狀態的(定義在類中的)方法。
函式的本質就是一段有特定功能、可以重複使用的**,這段**已經被提前編寫好了,並且為其起乙個「好聽」的名字。在後續編寫程式過程中,如果需要同樣的功能,直接通過起好的名字就可以呼叫這段**。
很顯然,這樣的答案並沒有讓人搞明白類和函式到底不一樣在**。但是裡面提到了類是建立乙個物件,所以類是物件導向程式設計(object oriented programming)。也就是我們常說的oop。而oop高度關注的是**的組織,可重用性和封裝。
第乙個例子
上面的官方解釋上去還是很抽象,那麼我們開始說人話。簡單來說當python中沒有可以完全表達我們要表示的內容的資料型別時,那麼就需要使用乙個類。來看下面的例子。
如果我正在計算某人的年齡,則只需使用int因為它可以滿足我的需求。如果我們需要在遊戲中表示像敵人之類的東西,則可以建立乙個類則可以建立乙個類enemy,其中包含諸如health和armor的資料,幷包含諸如fire_weapon射擊時的功能。然後,我們還可以建立另乙個類flyingenemy,enemy該類從該類繼承所有內容,但又具有乙個fly方法,因此具有其他功能。
第二個例子
some_song =
# 其他資料型別的結構也類似
# 一些函式
def play_song(song):
# 獲取歌的路徑
path = song["filepath"]
call_some_library_function(path)
def play_album(album):
# 找到**裡所有的歌曲
# 分別呼叫play_song
def play_artist(artist):
# 找到這位藝術家所有的**
# 分別呼叫play_album
def play_playlist(playlist):
# 分別呼叫play_song
class song:
def __init__(self, title, artist, album, duration, filepath):
self.title = title
self.artist = artist
self.album = album
self.duration = duration
self.filepath = filepath
def play(self):
path = self.filepath
call_some_library_function(path)
這樣就定義了如何建立乙個新的song物件。該方法將字段值作為引數,並將它們作為物件的屬性賦值。self是乙個特殊引數(名稱不保留;它可以被稱為任何東西),它是對物件本身的引用。是一種從同一物件的其他方法內部訪問屬性和方法的方法。當我們從物件外部訪問它們時(要使用play方法時將執行此操作),則可以使用在該範圍內為物件指定的任何名稱。
那麼在之前:
# some_song是上面定義的歌
play_song(some_song)
在使用class之後:
# self引數沒有在這裡傳遞;它會自動新增
some_song = song("yellow submarine",
the_beatles,
yellow_submarine_album,
insert_time_object_here,
"path/to/file/on/disk"
)some_song.play()
第三個例子
我們繼續看下面兩段**來實現輸出一些學生的成績,首先是使用類:
class student(object):
def __init__(self, name, age, gender, level, grades=none):
self.name = name
self.age = age
self.gender = gender
self.level = level
self.grades = grades or {}
def setgrade(self, course, grade):
self.grades[course] = grade
def getgrade(self, course):
return self.grades[course]
def getgpa(self):
return sum(self.grades.values())/len(self.grades)
# 定義一些學生
john = student("john", 12, "male", 6, )
jane = student("jane", 12, "female", 6, )
# 現在我們可以很容易地得到分數
print(john.getgpa())
print(jane.getgpa())
再來看看用函式怎麼實現
def calculategpa(gradedict):
return sum(gradedict.values())/len(gradedict)
students = {}
name, age, gender, level, grades = "name", "age", "gender", "level", "grades"
john, jane = "john", "jane"
math = "math"
students[john] = {}
students[john][age] = 12
students[john][gender] = "male"
students[john][level] = 6
students[john][grades] =
students[jane] = {}
students[jane][age] = 12
students[jane][gender] = "female"
students[jane][level] = 6
students[jane][grades] =
print(calculategpa(students[john][grades]))
print(calculategpa(students[jane][grades]))
這兩段**都實現了輸出學生的成績,但是在使用函式的時候,我們需要記住學生是誰,成績儲存在**,似乎不是很困難(如果需要輸出的學生更多呢),但是oop避免了這一點。並且**也更加pythonic。
結束語最後,讓我們回到剛開始的問題上來,上面說了這麼多類的好處所以我們就應該更多的去使用類嗎?並不是!
其實從某種意義上來說,類並不比函式更好。只是在某些情況下使用類能夠更好的幫助我們寫**。所以如果發現自己使用各種資料集呼叫some_function(data),那麼將其用類表示為data.some_function()可能提高我們的效率。至於到底在何時使用類,我們來看看其他程式設計師的理解
代價 損失 目標函式,傻傻分不清楚
背景 aimer 看國外教程的時候,或者看 的時候,會看到這三種函式 loss funciton 損失函式 cost function 代價函式 objective function 目標函式 三者傻傻分不清楚。看起來這三個好像是講的乙個東西,但細細琢磨,才發現是有些不同的。首先來看看andrew在...
傻傻分不清楚 一 Get和Post
寫這篇部落格之前,看了裡一位前輩寫的關於get post區別的文章,更是一頭霧水,原文 get和post有什麼區別?及為什麼網上的多數答案都是錯的。瞬間顛覆我之前的觀點,於是各種找資料,參考 http中get與post的區別,總算有了一點眉目,get和post是http協議傳送資料的兩種方式,那就先...
公鑰和私鑰,傻傻分不清楚!
公鑰用於加密,私鑰用於解密。私鑰用於簽名,公鑰用於驗證。綜上所述 公鑰和秘鑰,這一對組合,一般成對出現,共有兩種用途 1 加密 2 簽名 所以不要把這個東西搞混了,非常容易混淆。jwt實現單點登入功能時,使用私鑰進行簽名,公鑰分配出去。每乙個微服務都儲存有乙份公鑰,當微服務想要訪問其他服務時,經過閘...