Python 函數(shù)定義以及參數(shù)傳遞
創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站建設(shè)、成都做網(wǎng)站、貢井網(wǎng)絡(luò)推廣、小程序設(shè)計(jì)、貢井網(wǎng)絡(luò)營(yíng)銷、貢井企業(yè)策劃、貢井品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供貢井建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com
1.函數(shù)定義
#形如def func(args...):
doSomething123
以關(guān)鍵字def 開頭,后面是函數(shù)名和參數(shù)下面是函數(shù)處理過(guò)程。
舉例:
def add( a, b ):
return a+b12
參數(shù)可以設(shè)定默認(rèn)值,如:
def add( a, b=10 ): #注意:默認(rèn)值參數(shù)只會(huì)運(yùn)算一次
return a+b12
默認(rèn)值參數(shù)只會(huì)運(yùn)算一次是什么意思?
def func( a, b=[] ): #b的默認(rèn)值指向一個(gè)空的列表,每次不帶默認(rèn)值都會(huì)指向這塊內(nèi)存
b.append(a) return b
print(func(1))#向默認(rèn)的空列表里加入元素1 ,默認(rèn)列表里已經(jīng)是[1]print(func(2))#向默認(rèn)的列表里加入元素2,默認(rèn)列表里已經(jīng)是[1,2]print(func(3,[]))#向b指向的空列表里加入元素1 ,默認(rèn)列表里還是[1,2]print(func(4))#向默認(rèn)的列表里加入元素4,默認(rèn)列表里已經(jīng)是[1,2,4]'''
結(jié)果:
[1]
[1, 2]
[3]
[1, 2, 4]
'''12345678910111213141516
這下明白為什么默認(rèn)參數(shù)只計(jì)算一次了吧,函數(shù)參數(shù)不傳遞時(shí)默認(rèn)值總是指向固定的內(nèi)存空間,就是第一次計(jì)算的空間。
2.參數(shù)傳遞
def func(a, b):
print('a=%d, b=%d' % (a,b) )12
在使用函數(shù)時(shí)可以如下方式,結(jié)果都是相同的
func(10,20) #不使用參數(shù)名,需要按參數(shù)順序傳遞func(a=10,b=20) #使用參數(shù)名可以不按順序傳遞func(b=20,a=10)#結(jié)果:a=10, b=20a=10, b=20a=10, b=201234567
如果函數(shù)定義形式如下方式:
def func(*args): #這種定義會(huì)把傳遞的參數(shù)包成元組
print(args,type(args))
func(10,20)#結(jié)果:#(10, 20) class 'tuple'1234567
舉一個(gè)和上述過(guò)程相反的例子:
def func(a,b):
print('a=%d, b=%d' % (a,b) )
a = (10, 20)
func(*a) #在調(diào)用函數(shù)使用`*`則會(huì)把元組解包成單個(gè)變量按順序傳入函數(shù)#結(jié)果:a=10, b=20123456
總結(jié):*號(hào)在定義函數(shù)參數(shù)時(shí),傳入函數(shù)的參數(shù)會(huì)轉(zhuǎn)換成元組,如果 *號(hào)在調(diào)用時(shí)則會(huì)把元組解包成單個(gè)元素。
另一種定義:
def func(**kw):#使用**定義參數(shù)會(huì)把傳入?yún)?shù)包裝成字典dict
print(kw, type(kw) )
func(a=10,b=20)#這種函數(shù)在使用時(shí)必須指定參數(shù)值,使用key=value這種形式#結(jié)果:{'b': 20, 'a': 10} class 'dict'12345
相反的例子:
def func(a,b):
print('a=%d, b=%d' % (a,b) )
d = {'a':10, 'b':20 }
func(**d) #在調(diào)用時(shí)使用**會(huì)把字典解包成變量傳入函數(shù)。12345
def func(*args, **kw):#這種形式的定義代表可以接受任意類型的參數(shù)
print(args,kw )12
總結(jié):**號(hào)在定義函數(shù)參數(shù)時(shí),傳入函數(shù)的參數(shù)會(huì)轉(zhuǎn)換成字典,如果 **號(hào)在調(diào)用時(shí)則會(huì)把字典解包成單個(gè)元素。
lambda表達(dá)式
lambda表達(dá)式就是一種簡(jiǎn)單的函數(shù)
形如 f = lambda 參數(shù)1,參數(shù)2: 返回的計(jì)算值
例如:
add = lambda x,y: x+y
print(add(1,2))'''
結(jié)果:3
'''12345
python 的函數(shù)參數(shù)類型分為4種:
1.位置參數(shù):調(diào)用函數(shù)時(shí)根據(jù)函數(shù)定義的參數(shù)位置來(lái)傳遞參數(shù),位置參數(shù)也可以叫做必要參數(shù),函數(shù)調(diào)用時(shí)必須要傳的參數(shù)。
當(dāng)參數(shù)滿足函數(shù)必要參數(shù)傳參的條件,函數(shù)能夠正常執(zhí)行:
add(1,2) #兩個(gè)參數(shù)的順序必須一一對(duì)應(yīng),且少一個(gè)參數(shù)都不可以
當(dāng)我們運(yùn)行上面的程序,輸出:
當(dāng)函數(shù)需要兩個(gè)必要參數(shù),但是調(diào)用函數(shù)只給了一個(gè)參數(shù)時(shí),程序會(huì)拋出異常
add(1)
當(dāng)我們運(yùn)行上面的程序,輸出:
當(dāng)函數(shù)需要兩個(gè)必要參數(shù),但是調(diào)用函數(shù)只給了三個(gè)參數(shù)時(shí),程序會(huì)拋出異常
add(1,2,3)
當(dāng)我們運(yùn)行上面的程序,輸出
2.關(guān)鍵字參數(shù):用于函數(shù)調(diào)用,通過(guò)“鍵-值”形式加以指定。可以讓函數(shù)更加清晰、容易使用,同時(shí)也清除了參數(shù)的順序需求。
add(1,2) # 這種方式傳參,必須按順序傳參:x對(duì)應(yīng)1,y對(duì)應(yīng):2
add(y=2,x=1) #以關(guān)健字方式傳入?yún)?shù)(可以不按順序)
正確的調(diào)用方式
add(x=1, y=2)
add(y=2, x=1)
add(1, y=2)
以上調(diào)用方式都是允許的,能夠正常執(zhí)行
錯(cuò)誤的調(diào)用方式
add(x=1, 2)
add(y=2, 1)
以上調(diào)用都會(huì)拋出SyntaxError 異常
上面例子可以看出:有位置參數(shù)時(shí),位置參數(shù)必須在關(guān)鍵字參數(shù)的前面,但關(guān)鍵字參數(shù)之間不存在先后順序的
3.默認(rèn)參數(shù):用于定義函數(shù),為參數(shù)提供默認(rèn)值,調(diào)用函數(shù)時(shí)可傳可不傳該默認(rèn)參數(shù)的值,所有位置參數(shù)必須出現(xiàn)在默認(rèn)參數(shù)前,包括函數(shù)定義和調(diào)用,有多個(gè)默認(rèn)參數(shù)時(shí),調(diào)用的時(shí)候,既可以按順序提供默認(rèn)參數(shù),也可以不按順序提供部分默認(rèn)參數(shù)。當(dāng)不按順序提供部分默認(rèn)參數(shù)時(shí),需要把參數(shù)名寫上
默認(rèn)參數(shù)的函數(shù)定義
上面示例第一個(gè)是正確的定義位置參數(shù)的方式,第二個(gè)是錯(cuò)誤的,因?yàn)槲恢脜?shù)在前,默認(rèn)參數(shù)在后
def add1(x=1,y) 的定義會(huì)拋出如下異常
默認(rèn)參數(shù)的函數(shù)調(diào)用
注意:定義默認(rèn)參數(shù)默認(rèn)參數(shù)最好不要定義為可變對(duì)象,容易掉坑
不可變對(duì)象:該對(duì)象所指向的內(nèi)存中的值不能被改變,int,string,float,tuple
可變對(duì)象,該對(duì)象所指向的內(nèi)存中的值可以被改變,dict,list
這里只要理解一下這個(gè)概念就行或者自行百度,后續(xù)會(huì)寫相關(guān)的專題文章講解
舉一個(gè)簡(jiǎn)單示例
4.可變參數(shù)區(qū)別:定義函數(shù)時(shí),有時(shí)候我們不確定調(diào)用的時(shí)候會(huì)多少個(gè)參數(shù),j就可以使用可變參數(shù)
可變參數(shù)主要有兩類:
*args: (positional argument) 允許任意數(shù)量的可選位置參數(shù)(參數(shù)),將被分配給一個(gè)元組, 參數(shù)名前帶*,args只是約定俗成的變量名,可以替換其他名稱
**kwargs:(keyword argument) 允許任意數(shù)量的可選關(guān)鍵字參數(shù),,將被分配給一個(gè)字典,參數(shù)名前帶**,kwargs只是約定俗成的變量名,可以替換其他名稱
*args 的用法
args 是用來(lái)傳遞一個(gè)非鍵值對(duì)的可變數(shù)量的參數(shù)列表給函數(shù)
語(yǔ)法是使用 符號(hào)的數(shù)量可變的參數(shù); 按照慣例,通常是使用arg這個(gè)單詞,args相當(dāng)于一個(gè)變量名,可以自己定義的
在上面的程序中,我們使用* args作為一個(gè)可變長(zhǎng)度參數(shù)列表傳遞給add()函數(shù)。 在函數(shù)中,我們有一個(gè)循環(huán)實(shí)現(xiàn)傳遞的參數(shù)計(jì)算和輸出結(jié)果。
還可以直接傳遞列表或者數(shù)組的方式傳遞參數(shù),以數(shù)組或者列表方式傳遞參數(shù)名前面加(*) 號(hào)
理解* * kwargs
**kwargs 允許你將不定長(zhǎng)度的鍵值對(duì), 作為參數(shù)傳遞給函數(shù),這些關(guān)鍵字參數(shù)在函數(shù)內(nèi)部自動(dòng)組裝為一個(gè)dict
下篇詳細(xì)講解 *args, **kwargs 的參數(shù)傳遞和使用敬請(qǐng)關(guān)注
【常見的內(nèi)置函數(shù)】
1、enumerate(iterable,start=0)
是python的內(nèi)置函數(shù),是枚舉、列舉的意思,對(duì)于一個(gè)可迭代的(iterable)/可遍歷的對(duì)象(如列表、字符串),enumerate將其組成一個(gè)索引序列,利用它可以同時(shí)獲得索引和值。
2、zip(*iterables,strict=False)
用于將可迭代的對(duì)象作為參數(shù),將對(duì)象中對(duì)應(yīng)的元素打包成一個(gè)個(gè)元組,然后返回由這些元組組成的列表。如果各個(gè)迭代器的元素個(gè)數(shù)不一致,則返回列表長(zhǎng)度與最短的對(duì)象相同,利用*號(hào)操作符,可以將元組解壓為列表。
3、filter(function,iterable)
filter是將一個(gè)序列進(jìn)行過(guò)濾,返回迭代器的對(duì)象,去除不滿足條件的序列。
4、isinstance(object,classinfo)
是用來(lái)判斷某一個(gè)變量或者是對(duì)象是不是屬于某種類型的一個(gè)函數(shù),如果參數(shù)object是classinfo的實(shí)例,或者object是classinfo類的子類的一個(gè)實(shí)例,
返回True。如果object不是一個(gè)給定類型的的對(duì)象, 則返回結(jié)果總是False
5、eval(expression[,globals[,locals]])
用來(lái)將字符串str當(dāng)成有效的表達(dá)式來(lái)求值并返回計(jì)算結(jié)果,表達(dá)式解析參數(shù)expression并作為Python表達(dá)式進(jìn)行求值(從技術(shù)上說(shuō)是一個(gè)條件列表),采用globals和locals字典作為全局和局部命名空間。
【常用的句式】
1、format字符串格式化
format把字符串當(dāng)成一個(gè)模板,通過(guò)傳入的參數(shù)進(jìn)行格式化,非常實(shí)用且強(qiáng)大。
2、連接字符串
常使用+連接兩個(gè)字符串。
3、if...else條件語(yǔ)句
Python條件語(yǔ)句是通過(guò)一條或多條語(yǔ)句的執(zhí)行結(jié)果(True或者False)來(lái)決定執(zhí)行的代碼塊。其中if...else語(yǔ)句用來(lái)執(zhí)行需要判斷的情形。
4、for...in、while循環(huán)語(yǔ)句
循環(huán)語(yǔ)句就是遍歷一個(gè)序列,循環(huán)去執(zhí)行某個(gè)操作,Python中的循環(huán)語(yǔ)句有for和while。
5、import導(dǎo)入其他腳本的功能
有時(shí)需要使用另一個(gè)python文件中的腳本,這其實(shí)很簡(jiǎn)單,就像使用import關(guān)鍵字導(dǎo)入任何模塊一樣。
從零開始用Python構(gòu)建神經(jīng)網(wǎng)絡(luò)
動(dòng)機(jī):為了更加深入的理解深度學(xué)習(xí),我們將使用 python 語(yǔ)言從頭搭建一個(gè)神經(jīng)網(wǎng)絡(luò),而不是使用像 Tensorflow 那樣的封裝好的框架。我認(rèn)為理解神經(jīng)網(wǎng)絡(luò)的內(nèi)部工作原理,對(duì)數(shù)據(jù)科學(xué)家來(lái)說(shuō)至關(guān)重要。
這篇文章的內(nèi)容是我的所學(xué),希望也能對(duì)你有所幫助。
神經(jīng)網(wǎng)絡(luò)是什么?
介紹神經(jīng)網(wǎng)絡(luò)的文章大多數(shù)都會(huì)將它和大腦進(jìn)行類比。如果你沒(méi)有深入研究過(guò)大腦與神經(jīng)網(wǎng)絡(luò)的類比,那么將神經(jīng)網(wǎng)絡(luò)解釋為一種將給定輸入映射為期望輸出的數(shù)學(xué)關(guān)系會(huì)更容易理解。
神經(jīng)網(wǎng)絡(luò)包括以下組成部分
? 一個(gè)輸入層,x
? 任意數(shù)量的隱藏層
? 一個(gè)輸出層,?
? 每層之間有一組權(quán)值和偏置,W and b
? 為隱藏層選擇一種激活函數(shù),σ。在教程中我們使用 Sigmoid 激活函數(shù)
下圖展示了 2 層神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)(注意:我們?cè)谟?jì)算網(wǎng)絡(luò)層數(shù)時(shí)通常排除輸入層)
2 層神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)
用 Python 可以很容易的構(gòu)建神經(jīng)網(wǎng)絡(luò)類
訓(xùn)練神經(jīng)網(wǎng)絡(luò)
這個(gè)網(wǎng)絡(luò)的輸出 ? 為:
你可能會(huì)注意到,在上面的等式中,輸出 ? 是 W 和 b 函數(shù)。
因此 W 和 b 的值影響預(yù)測(cè)的準(zhǔn)確率. 所以根據(jù)輸入數(shù)據(jù)對(duì) W 和 b 調(diào)優(yōu)的過(guò)程就被成為訓(xùn)練神經(jīng)網(wǎng)絡(luò)。
每步訓(xùn)練迭代包含以下兩個(gè)部分:
? 計(jì)算預(yù)測(cè)結(jié)果 ?,這一步稱為前向傳播
? 更新 W 和 b,,這一步成為反向傳播
下面的順序圖展示了這個(gè)過(guò)程:
前向傳播
正如我們?cè)谏蠄D中看到的,前向傳播只是簡(jiǎn)單的計(jì)算。對(duì)于一個(gè)基本的 2 層網(wǎng)絡(luò)來(lái)說(shuō),它的輸出是這樣的:
我們?cè)?NeuralNetwork 類中增加一個(gè)計(jì)算前向傳播的函數(shù)。為了簡(jiǎn)單起見我們假設(shè)偏置 b 為0:
但是我們還需要一個(gè)方法來(lái)評(píng)估預(yù)測(cè)結(jié)果的好壞(即預(yù)測(cè)值和真實(shí)值的誤差)。這就要用到損失函數(shù)。
損失函數(shù)
常用的損失函數(shù)有很多種,根據(jù)模型的需求來(lái)選擇。在本教程中,我們使用誤差平方和作為損失函數(shù)。
誤差平方和是求每個(gè)預(yù)測(cè)值和真實(shí)值之間的誤差再求和,這個(gè)誤差是他們的差值求平方以便我們觀察誤差的絕對(duì)值。
訓(xùn)練的目標(biāo)是找到一組 W 和 b,使得損失函數(shù)最好小,也即預(yù)測(cè)值和真實(shí)值之間的距離最小。
反向傳播
我們已經(jīng)度量出了預(yù)測(cè)的誤差(損失),現(xiàn)在需要找到一種方法來(lái)傳播誤差,并以此更新權(quán)值和偏置。
為了知道如何適當(dāng)?shù)恼{(diào)整權(quán)值和偏置,我們需要知道損失函數(shù)對(duì)權(quán)值 W 和偏置 b 的導(dǎo)數(shù)。
回想微積分中的概念,函數(shù)的導(dǎo)數(shù)就是函數(shù)的斜率。
梯度下降法
如果我們已經(jīng)求出了導(dǎo)數(shù),我們就可以通過(guò)增加或減少導(dǎo)數(shù)值來(lái)更新權(quán)值 W 和偏置 b(參考上圖)。這種方式被稱為梯度下降法。
但是我們不能直接計(jì)算損失函數(shù)對(duì)權(quán)值和偏置的導(dǎo)數(shù),因?yàn)樵趽p失函數(shù)的等式中并沒(méi)有顯式的包含他們。因此,我們需要運(yùn)用鏈?zhǔn)角髮?dǎo)發(fā)在來(lái)幫助計(jì)算導(dǎo)數(shù)。
鏈?zhǔn)椒▌t用于計(jì)算損失函數(shù)對(duì) W 和 b 的導(dǎo)數(shù)。注意,為了簡(jiǎn)單起見。我們只展示了假設(shè)網(wǎng)絡(luò)只有 1 層的偏導(dǎo)數(shù)。
這雖然很簡(jiǎn)陋,但是我們依然能得到想要的結(jié)果—損失函數(shù)對(duì)權(quán)值 W 的導(dǎo)數(shù)(斜率),因此我們可以相應(yīng)的調(diào)整權(quán)值。
現(xiàn)在我們將反向傳播算法的函數(shù)添加到 Python 代碼中
為了更深入的理解微積分原理和反向傳播中的鏈?zhǔn)角髮?dǎo)法則,我強(qiáng)烈推薦 3Blue1Brown 的如下教程:
Youtube:
整合并完成一個(gè)實(shí)例
既然我們已經(jīng)有了包括前向傳播和反向傳播的完整 Python 代碼,那么就將其應(yīng)用到一個(gè)例子上看看它是如何工作的吧。
神經(jīng)網(wǎng)絡(luò)可以通過(guò)學(xué)習(xí)得到函數(shù)的權(quán)重。而我們僅靠觀察是不太可能得到函數(shù)的權(quán)重的。
讓我們訓(xùn)練神經(jīng)網(wǎng)絡(luò)進(jìn)行 1500 次迭代,看看會(huì)發(fā)生什么。 注意觀察下面每次迭代的損失函數(shù),我們可以清楚地看到損失函數(shù)單調(diào)遞減到最小值。這與我們之前介紹的梯度下降法一致。
讓我們看看經(jīng)過(guò) 1500 次迭代后的神經(jīng)網(wǎng)絡(luò)的最終預(yù)測(cè)結(jié)果:
經(jīng)過(guò) 1500 次迭代訓(xùn)練后的預(yù)測(cè)結(jié)果
我們成功了!我們應(yīng)用前向和方向傳播算法成功的訓(xùn)練了神經(jīng)網(wǎng)絡(luò)并且預(yù)測(cè)結(jié)果收斂于真實(shí)值。
注意預(yù)測(cè)值和真實(shí)值之間存在細(xì)微的誤差是允許的。這樣可以防止模型過(guò)擬合并且使得神經(jīng)網(wǎng)絡(luò)對(duì)于未知數(shù)據(jù)有著更強(qiáng)的泛化能力。
下一步是什么?
幸運(yùn)的是我們的學(xué)習(xí)之旅還沒(méi)有結(jié)束,仍然有很多關(guān)于神經(jīng)網(wǎng)絡(luò)和深度學(xué)習(xí)的內(nèi)容需要學(xué)習(xí)。例如:
? 除了 Sigmoid 以外,還可以用哪些激活函數(shù)
? 在訓(xùn)練網(wǎng)絡(luò)的時(shí)候應(yīng)用學(xué)習(xí)率
? 在面對(duì)圖像分類任務(wù)的時(shí)候使用卷積神經(jīng)網(wǎng)絡(luò)
我很快會(huì)寫更多關(guān)于這個(gè)主題的內(nèi)容,敬請(qǐng)期待!
最后的想法
我自己也從零開始寫了很多神經(jīng)網(wǎng)絡(luò)的代碼
雖然可以使用諸如 Tensorflow 和 Keras 這樣的深度學(xué)習(xí)框架方便的搭建深層網(wǎng)絡(luò)而不需要完全理解其內(nèi)部工作原理。但是我覺(jué)得對(duì)于有追求的數(shù)據(jù)科學(xué)家來(lái)說(shuō),理解內(nèi)部原理是非常有益的。
這種練習(xí)對(duì)我自己來(lái)說(shuō)已成成為重要的時(shí)間投入,希望也能對(duì)你有所幫助
1、函數(shù)定義
①使用def關(guān)鍵字定義函數(shù)
②
def 函數(shù)名(參數(shù)1.參數(shù)2.參數(shù)3...):
"""文檔字符串,docstring,用來(lái)說(shuō)明函數(shù)的作用"""
#函數(shù)體
return 表達(dá)式
注釋的作用:說(shuō)明函數(shù)是做什么的,函數(shù)有什么功能。
③遇到冒號(hào)要縮進(jìn),冒號(hào)后面所有的縮進(jìn)的代碼塊構(gòu)成了函數(shù)體,描述了函數(shù)是做什么的,即函數(shù)的功能是什么。Python函數(shù)的本質(zhì)與數(shù)學(xué)中的函數(shù)的本質(zhì)是一致的。
2、函數(shù)調(diào)用
①函數(shù)必須先定義,才能調(diào)用,否則會(huì)報(bào)錯(cuò)。
②無(wú)參數(shù)時(shí)函數(shù)的調(diào)用:函數(shù)名(),有參數(shù)時(shí)函數(shù)的調(diào)用:函數(shù)名(參數(shù)1.參數(shù)2.……)
③不要在定義函數(shù)的時(shí)候在函數(shù)體里面調(diào)用本身,否則會(huì)出不來(lái),陷入循環(huán)調(diào)用。
④函數(shù)需要調(diào)用函數(shù)體才會(huì)被執(zhí)行,單純的只是定義函數(shù)是不會(huì)被執(zhí)行的。
⑤Debug工具中Step into進(jìn)入到調(diào)用的函數(shù)里,Step Into My Code進(jìn)入到調(diào)用的模塊里函數(shù)。