類和函式傻傻分不清楚?三個例子講明白

2021-10-03 22:44:14 字數 4272 閱讀 8861

前言

前兩天一位小夥伴問了這樣乙個問題:雖然已經使用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實現單點登入功能時,使用私鑰進行簽名,公鑰分配出去。每乙個微服務都儲存有乙份公鑰,當微服務想要訪問其他服務時,經過閘...