python基礎篇——函式
??hello!我是wakeyo_J,每天一個konwledge point,一起學python,讓技術無限發散,
函式
- python基礎篇——函式
- 1. 函式的來源
- 2. 函式基本定義
- 3. 自定義函式第一步
- 3.1 不帶引數的函式
- 3.2 帶引數函式
- 3.3 帶回傳值函式
- 4. 自定義函式完善
- 4.1 函式檔案
- 4.2 函式健壯
- 5. 將函式放到模塊中
- 5.1 建立函式模塊
- 5.2 呼叫函式模塊
- 5.2.1 用import陳述句匯入整個函式模塊
- 5.2.2 用import陳述句匯入指定函式
- 5.2.3 用import陳述句匯入所有函式
- 5.2.4 模塊名、函式別名方式
- 5.3 模塊搜索路徑
- 6. 自定義函式第二步
- 6.1 引數變換
- 6.1.1 位置引數
- 6.1.2 關鍵字引數
- 6.1.3 默認值
- 6.1.4 不定長引數 *、**
- 6.2 傳遞元組、串列、字典值
- 6.2.1 傳遞元組
- 6.2.2 傳遞串列
- 6.2.3 傳遞字典
- 6.2.4 傳遞串列、字典后的問題
- 6.2.5 函式傳遞物件總結
- 6.3 函式與變數作用域
- 6.3.1 全域部變數與區域變數
- 6.3.2 global關鍵字
- 6.3.3 閉包
- 6.3.4 nonlocal關鍵字
- 6.4 匿名函式
- 6.5 遞回函式
- 7. 裝飾器
- 總結
1. 函式的來源
??早期的高級語言屬于程序語言,程式員是按照順序一行一行的撰寫代碼,然后順序執行,而且經常出現大量重復的代碼行,這樣就導致代碼非常的臃腫、除錯困難、閱讀麻煩,當代碼要實作的功能越來越強大,相應的問題也就越來越多,為了有效解決上述問題,計算機語言學家便將功能相同的代碼單獨提取出來,獨立實作一個功能,供需要的代碼呼叫,這就是函式的來源,
函式代碼的優點
(1)代碼簡練
(2)提高代碼的撰寫效率和質量
(3)代碼的功能可以自由共享
2. 函式基本定義
函式:指通過專門的代碼組織,用來實作特定功能的代碼段,具有相對的獨立性,可以被其他代碼重復呼叫,
- 函式是一段具有特定功能的、可重用的陳述句組
- 函式是一種功能的抽象,一般函式表達特定的功能
- 兩個作用:降低編程難度和代碼復用

- 函式定義基本語法
def <函式名>(<引數(0個或多個)>):
<函式體>
return <回傳值>
- 函式使用格式說明
標準自定義函式由def關鍵字、函式名、“([引數]): ”、函式體、[return回傳值]五部分組成,
1)def關鍵字
python中函式定義以def關鍵字開始,其后空一格跟函式名
2)自定義函式名
在python中,函式名由字母、數字、下劃線組成,也就是小寫字母a~z、大寫字母A-Z、下劃線(_)和數字0-9等組成且命名時數字不能作為名稱的首字符,
(1)自定義函式名不能和現有內置函式名發生沖突,如:不能使用del命名
(2)名稱本身要準確表達函式的功能,建議使用英文單詞開頭,英文單詞之間可以用下劃線,如:find_factor,可以清楚的表達“求因數”,
3)([引數]):
中括號中的引數可有可無,小括號后面的冒號(:)是python函式的基本格式要求,不能省略,這里的引數傳遞物件包括數字、字串、元組、串列、字典以及類物件,
4)函式體
函式體是實作函式功能的代碼段,
5)[return回傳值]
return后面空一格,跟需要回傳的值,帶有中括號,表明函式可以由回傳值,也可以沒回傳值,
3. 自定義函式第一步
3.1 不帶引數的函式
- 不帶引數函式格式
def 函式名():
函式體
- 案例
>>> def factor_no_para():
i=1
nums=10
print('%d的因數是:'%nums)
while i<=nums: #回圈求10的因數
if nums%i==0: #能整除的是10的因數
print("%d"%i)
i += 1
>>> factor_no_para()
10的因數是:
1
2
5
10
>>> tt=type(factor_no_para)
>>> tt
<class 'function'>
>>>
3.2 帶引數函式
- 帶引數函式格式
def 函式名(引數):
函式體
- 案例
def find_factor(nums):
i=1
str1=""
print("%d的因數是:"%nums)
while i<=nums:
if nums%i==0:
str1 = str1+" "+str(i)
i += 1
print(str1)
num_L=[10,15,18,20]
i = 0
num_len=len(num_L)
while i<num_len:
find_factor(num_L[i])
i+=1
結果:

3.3 帶回傳值函式
- 帶回傳值函式格式
def 函式名([引數]):
函式體
return 回傳值 #回傳值支持python語言所支持的任何物件
- 函式回傳值
不帶return陳述句的函式,默認回傳None值,
def factor_no_para():
i=1
nums=10
print('%d的因數是:'%nums)
while i<=nums:
if nums%i==0:
print("%d"%i)
i += 1
結果:

3. 案例
def find_factor(nums):
i=1
str1=""
print("%d的因數是:"%nums)
while i<=nums:
if nums%i==0:
str1 = str1+" "+str(i)
i += 1
return str1
num_L=[10,15,18,20]
i = 0
num_len=len(num_L)
return_str=''
while i<num_len:
return_str=find_factor(num_L[i])
print("%d的因數是:%s"%(num_L[i],return_str))
i+=1
結果:

4. 自定義函式完善
4.1 函式檔案
自定義函式撰寫完成后,需要考慮到使用的方便性,如編程人員過了幾個月或者幾年后都能輕易地知道函式的功能及如何使用,由此,需要對自定義函式建立相應的函式檔案,函式檔案在函式中通常用三引號(’’’)來表示,
def find_factor(nums):
'''
find_factor 自定義函式
nums 傳遞一個正整數的引數
以字串形式回傳一個正整數的所有因數
'''
i=1
str1=""
print("%d的因數是:"%nums)
while i<=nums:
if nums%i==0:
str1 = str1+" "+str(i)
i += 1
return str1
help(find_factor)
結果:

4.2 函式健壯
def find_factor(nums):
'''
find_factor 自定義函式
nums 傳遞一個正整數的引數
以字串形式回傳一個正整數的所有因數
'''
i=1
str1=""
print("%d的因數是:"%nums)
while i<=nums:
if nums%i==0:
str1 = str1+" "+str(i)
i += 1
return str1
##help(find_factor)
find_factor('a')
運行結果報錯:

傳遞引數型別出錯,不支持字串型別的值,對函式進一步改進,增加函式的健壯性,
def find_factor(nums):
'''
find_factor 自定義函式
nums 傳遞一個正整數的引數
以字串形式回傳一個正整數的所有因數
'''
if type(nums) != int:
print("輸入值型別錯誤,必須是整數")
return
elif nums<=0:
print("輸入值的范圍出錯,必須是整數!")
return
i=1
str1=""
print("%d的因數是:"%nums)
while i<=nums:
if nums%i==0:
str1 = str1+" "+str(i)
i += 1
return str1
find_factor('a')
結果:

5. 將函式放到模塊中
自定義函式建立后,如果需要被其他代碼檔案呼叫(以.py為擴展名的檔案);或者通過共享,讓其他程式員使用;或者需要通過正式的商業發布,讓全世界的程式員使用,就需要將函式代碼單獨放到一個可以共享的地方,在python中通過建立獨立的函式模塊檔案(以.py為擴展名的檔案),共享給其他代碼檔案呼叫,
5.1 建立函式模塊
(1)在python語言編輯器中,新建立一個空白的代碼檔案,用于存放自定義函式代碼,如建立檔案名為test_function.py的空函式模塊檔案,
(2)撰寫并除錯完成自定義函式代碼
(3)把只屬于自定義函式的代碼復制到函式模塊檔案上,若有多個自定義函式,按順序復制保存即可,

5.2 呼叫函式模塊
5.2.1 用import陳述句匯入整個函式模塊
匯入格式:import 函式模塊名
呼叫模塊檔案中的函式格式:模塊名.函式名
import test_function
print(test_function.find_factor(8))
結果:

5.2.2 用import陳述句匯入指定函式
匯入格式:from 模塊名 import 函式名1[,函式名2,…]
from test_function import find_factor
print(find_factor(8))
結果:

5.2.3 用import陳述句匯入所有函式
匯入格式:from 模塊名 import *
“*”代表指定模塊檔案里的所有函式
test_function.py模塊展示:

呼叫代碼:
from test_function import *
print(find_factor(8))
say_ok()
結果:

5.2.4 模塊名、函式別名方式
在匯入模塊、函式程序中發現模塊名、函式名過長(或函式名稱沖突),可以通過as陳述句定義別名來解決,
格式:模塊名[函式名] as 別名
>>> import test_function as t1
>>> t1.find_factor(8)
8的因數是:
' 1 2 4 8'
>>> from test_function import find_factor as f1
>>> f1(8)
8的因數是:
' 1 2 4 8'
>>>
5.3 模塊搜索路徑
當函式模塊檔案多變時,需要把函式檔案獨立放到一個子檔案夾下,方便統一管理,但是在不同檔案夾下的模塊呼叫需要解決路徑問題,不然會報“找不到模塊”英文提示,且程式無法正常運行,可以用sys.path方法指定需要訪問的函式模塊檔案,

import sys
sys.path[0]='G:\Python\test\代碼\第六章\\function'
from test_function import *
print(find_factor(8))
say_ok()
6. 自定義函式第二步
6.1 引數變換
6.1.1 位置引數
位置引數就是傳遞引數值時,必須和函式定義的引數一一對應,位置不能打亂,
def test(name,age):
print("姓名%s,年齡%s"%(name,age))
test('wky',20)
test(20,'wky')
#結果
姓名wky,年齡20
錯誤位置:
姓名20,年齡wky
6.1.2 關鍵字引數
為了避免傳遞值出錯,提供了“引數名=值”的方式,在呼叫函式時顯示表示,而且無序考慮引數的位置順序,
test(name='wky',age=20)
test(age=20,name='lyj')
test('wky',age=20) #部分指定時,左邊可以不指定,從右邊指定開始
結果:
姓名wky,年齡20
姓名lyj,年齡20
姓名wky,年齡20
#說明:
test(name='wky',20) #呼叫會出錯,不支持左邊指定,右邊不指定方式
6.1.3 默認值
為引數預先設定默認值,當沒有傳遞引數值時,該引數自動選自默認值,
def test(name='lyj',age=18):
print("姓名%s,年齡%s"%(name,age))
#函式呼叫
test(18)
test()
test('wky',20)
#結果:
姓名18,年齡18 #函式默認輸入一個值的情況下,把值賦給第一個引數
姓名lyj,年齡18
姓名wky,年齡20
對于自定義函式設定默認值,允許左邊的引數沒有默認值,右邊的有;反過來則不行,
def test(name='',age):
print("姓名%s,年齡%s"%(name,age))
6.1.4 不定長引數 、*
- 傳遞任意數量的引數值
使用格式:*函式名([param1,param2,…]paramX)
帶“*”的paramX引數,可以以接收任意數量的值,但是一個自定義函式只能有一個帶"*"的引數,而且只能放置最右邊的引數中,否則自定義函式執行時報語法錯誤,
def watermelon(name,*attributes):
print(name)
print(type(attributes))
description=''
for get_t in attributes:
description += ' ' +get_t
print(description)
watermelon('西瓜','甜','圓形','綠色')
print('-'*30)
watermelon('西瓜','甜','圓形','綠色','紅瓤','無籽')
#結果:
西瓜
<class 'tuple'>
甜 圓形 綠色
------------------------------
西瓜
<class 'tuple'>
甜 圓形 綠色 紅瓤 無籽
- 傳遞任意數量的鍵值對
使用格式:函式名([param1,param2,…]**paramX)
帶“**”paramX引數用法和帶“*”用法類似,區別:傳遞的是鍵值對,
def watermelon(name,**attributes):
print(name)
print(type(attributes))
return attributes
print(watermelon('西瓜',taste='甜',shape='圓形',colour='綠色'))
#結果
西瓜
<class 'dict'>
{'taste': '甜', 'shape': '圓形', 'colour': '綠色'}
6.2 傳遞元組、串列、字典值
6.2.1 傳遞元組
def watermelon(name,attributes):
print(name)
print(type(attributes))
return attributes
##get_t = watermelon('西瓜',('甜','圓形','綠色'))
##print(get_t)
print(watermelon('西瓜',('甜','圓形','綠色')))
結果:

6.2.2 傳遞串列
def watermelon(name,attributes):
print(name)
print(type(attributes))
return attributes
##get_t = watermelon('西瓜',['甜','圓形','綠色'])
##print(get_t)
print(watermelon('西瓜',['甜','圓形','綠色']))
結果:

6.2.3 傳遞字典
def watermelon(name,attributes):
print(name)
print(type(attributes))
return attributes
attri={'taste':"甜",'shape':"圓形",'colour':"綠色"}
print(watermelon('西瓜',attri))
結果:

6.2.4 傳遞串列、字典后的問題
在自定義函式內獲取從引數傳遞過來的串列、字典物件后,若在函式內部對它們的元素進行變動,則會同步影響外部傳遞的變數的元素,
def EditFrult(name,attributes):
attributes[0]=attributes[0]*0.9 #修改元素
return attributes
#呼叫函式
attri_L=[2,"甜","圓形","綠色"]
get_t = EditFrult("西瓜",attri_L)
print(get_t)
print(attri_L)
結果:

修改:
def EditFrult(name,attributes):
attributes[0]=attributes[0]*0.9 #修改元素
return attributes
#呼叫函式
attri_L=[2,"甜","圓形","綠色"]
get_t = EditFrult("西瓜",attri_L.copy())
print(get_t)
print(attri_L)
結果:

6.2.5 函式傳遞物件總結
函式引數值傳遞的物件可以分為不可變物件、可變物件,
- 不可變物件:在函式里進行值修改,會變成新的物件(在記憶體產生新的地址),包括:數字、字串、元組
- 可變物件:在函式里進值修改,函式內外還是同一物件,但是值同步發生變化,包括:串列、字典
6.3 函式與變數作用域
6.3.1 全域部變數與區域變數
區域變數和全域變數是不同變數
- 區域變數是函式內部的占位符,與全域變數可能重名但不同
- 函式運算結束后,區域變數被釋放
- 可以使用global保留字在函式內部使用全域變數

-
全域作用域(全域變數)
? 全域作用域在程式執行時創建,在程式執行結束時銷毀
? 所有函式以外的區域都是全域作用域
? 在全域作用域中定義的變數,都是全域變數,全域變數可以在程式的任意位置進行訪問

結果:

-
函式作用域(區域變數)
? 函式作用域在函式呼叫時創建,在呼叫結束時銷毀
? 函式每呼叫一次就會產生一個新的函式作用域
? 在函式作用域中定義的變數,都是區域變數,它只能在函式內部被訪問

6.3.2 global關鍵字
函式內部默認只能讀取全域變數的值,如需要修改全域變數,則需要使用global關鍵字進行宣告,否則在函式內修改全域變數會報英文錯誤,
- 規則1:
-
區域變數和全域變數是不同變數
-
區域變數是函式內部的占位符,與全域變數可能重名但不同
-
函式運算結束后,區域變數被釋放
-
可以使用global保留字在函式內部使用全域變數
-
函式使用global保留字宣告全域變數

- 規則2:區域變數為組合資料型別且為創建,等同于全域變數

結果:
[‘C’, ‘c’, ‘e’]

結果:
[‘C’, ‘c’]

結果:
[‘e’]
[‘C’, ‘c’]
6.3.3 閉包
閉包是介于全域變數和區域變數之間的一種特殊變數,
j = 5 #全域變數
def sum(): #外部函式
k=2 #閉包變數
def sum1(): #嵌套的內部函式
i=k+j #區域變數
return i
return sum1()
print("呼叫sum()結果%d"%sum())
結果:

6.3.4 nonlocal關鍵字
要在sum1函式中修改閉包變數k,則需要事先用nonlocal關鍵字宣告k,才能對它進行修改操作,修改的結果k變成函式sum1的區域變數,不提倡使用該方法傳遞值和修改值,
6.4 匿名函式
lambda函式回傳函式名作為結果
- lambda函式是一種匿名函式,就是沒有名字的函式
- 使用lambda保留字定義,函式名就是回傳結果
- lambda函式用于定義簡單的、能夠在一行內表示的函式
格式:lambda[para1,para2,…]:expression
特點:
(1)lambda后面沒有跟函式名
(2)[para1,para2,…]引數是可選的,任何型別的,引數往往在后面的expression中體現
(3)expression運算式實作匿名函式功能的程序,并回傳操作結果,具有通常函式return的功能
(4)整個匿名函式在一行實作所有定義,
>>> a = lambda x,y:x**y
>>> a(5,4)
625
6.5 遞回函式
? 遞回是解決問題的一種方式,它的整體思想,是將一個大問題分解為一個個的小問題,直到問題無法分解時,在去解決問題
? 遞回式函式有2個條件
? 1. 基線條件 問題可以被分解為最小問題,當滿足基線條件時,遞回就不執行了
? 2. 遞回條件 可以將問題繼續分解的條件
#遞回函式就是自己參考自己,遞回函式就是在函式里自己呼叫自己
# 無窮遞回
def fun():
fun()
fun()
#遞回的兩個條件
# 1.基線條件:問題可以被分解為最小的問題,當滿足基線條件的時候,再去解決問題
# 2.遞回條件:將問題繼續分解的條件
7. 裝飾器
在編程時,為了實作同樣的功能,需要更改代碼來實作,如果大量的修改代碼,不僅增加了作業量,還不方便后期維護,更加不符合ocp規則(o:open 開放對代碼的拓展,c :close 關閉對代碼的修改),裝飾器就是為了解決這寫問題被引入的,
def fun(a,b)
print('函式開始')
print('函式結束')
return a+b
def fun1(a,b):
return a*b
'''
如果fun函式要實作fun1函式同樣的輸出效果,可以直接復制print進行粘貼就行,\
但是這樣就出現了代碼的冗余、增加作業量等情況,那是否有辦法不用復制就直接那過來用呢?
'''
裝飾器的使用
- 通過裝飾器,可以在不修改原來函式的情況下來對函式進行擴展
- 在開發中,我們都是通過裝飾器來擴展函式的功能的
#裝飾器是一個特殊的閉包函式
#裝飾器
def ch(fn): #定義外層函式
def new_ch(*args,**kwargs): #定義一個內層函式,使用不定長引數進行傳參
print('函式開始')
fn(*args,**kwargs) #呼叫內層函式
print('函式結束')
return new_ch #回傳內層函式名
@ch #@ch=ch(fun),裝飾器的語法糖寫法 ,必須緊貼需要用到裝飾器的函式,即@ch必須在def fun():這個函式前
#函式
def fun(): #定義一個函式
print('我是fun函式')
#return '我是fun函式'
#函式呼叫方法一:通過裝飾器的語法糖寫法
fun()
#函式呼叫方法二:
# r = ch(fun) #此處是將函式名fun作為實參傳遞給fn,即fn = fun ,ch(fn) = new_ch = ch(fun) ,\
# # 內層函式呼叫ch(fn)() = new_ch() = ch(fun)()
# r()
總結
??本文屬于作者原創,轉載請注明出處,不足之處,希望大家能過給予寶貴的意見,如有侵權,請私信,每天一個knowledge point,一起學python,讓技術無限發散,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/291207.html
標籤:python
