1. 程式人生 > 其它 >Python學習-函式初識、函式引數使用

Python學習-函式初識、函式引數使用

記錄下python中函式的使用入門,函式就相當於java中的方法,想法都是減少重複程式碼,將公共部分抽取出來並可反覆呼叫,只是用法有些差別。

函式初識

假如python中沒有len方法,如果需要計算字串字元個數,或者列表長度,可以分別用如下方式實現。

如計算字串長度。

s='hgoahgohgohgogog'
# 假設python沒有len方法,如何計算上面字串的字元個數?
count=0
for item in s:
    count+=1
print(count)

如計算列表長度。

li=[1,2,3,4,5,6]
# 假設python沒有len方法,如何計算上面列表的元素個數?
count=0
for item in li:
    count+=1
print(count)

可以看出,上面的邏輯一樣,這時函式的想法呼之欲出,python中的函式就是java中的方法的意思,上面的邏輯可以使用函式實現,使用def關鍵字定義函式。

def my_len(x):
    count = 0
    for item in x:
        count += 1
    print(count)

函式名需要見名知意,函式體中儘量不要寫print列印東西。需要注意的是,如果函式中有return關鍵字,後面的程式碼將不再執行。

def meet(str):
    print('開啟'+str)
    print('出來了很多小姐姐')
    # 函式中有return,後面的程式碼不執行
    return
    print('懷著屌絲的心態瀏覽了下')
    print('10分鐘後')
    print('我好了')
    # 可以返回結果
    return '別做夢了'
# 呼叫  
ret=meet('探探')
print(ret)

執行結果可以看出,return後面的程式碼將不再執行。

開啟探探
出來了很多小姐姐
None

返回值只有單個的話,資料是什麼型別返回後就是什麼型別,如果函式使用return返回值有多個值,將以元祖形式返回給函式的執行者。

def test():
    return 'messi',123,[1,2,3]

print(test(),type(test())) # ('messi', 123, [1, 2, 3]) <class 'tuple'>

總結一下,return在函式中使用,效果如下。

  1. return 可以終止函式,後面的程式碼不再執行。
  2. return 單個值,是什麼型別就返回什麼型別 。
  3. return 多個值,以元祖形式返回。

函式的引數

函式的引數分為實參和形參,如下函式執行傳遞的引數(男、女、人妖)是實際引數,函式定義裡的那個引數(sex)就是形參。

# sex為形參
def my_print(sex):
    print('我的性別是%s' % (sex))
# 傳入實參
my_print('男')
my_print('女')
my_print('人妖')

函式引數的使用,可以分別從實參角度,形參角度來說明,最後引數使用中會混合位置引數、預設引數、還有其他形式的引數,如何正確的使用也記錄一下。

實參角度

(1)位置傳參

位置傳參就是傳入的實際引數位置需要和形參一一對應,不能順序錯誤。

# 實參和形參,從左至右,一一對應
def data_print(sex, age, hobby):
    print('我的性別是%s,年齡是%s,愛好是%s' % (sex, age, hobby))

data_print('男', '33', '女') # 我的性別是男,年齡是33,愛好是女

使用三元運算子比較數字大小,520傳入a的位置,1314傳入b的位置。

# 三元運算子
def my_max_2(a, b):
    return a if a > b else b

print(my_max_2(520, 1314)) # 1314

(2)關鍵字引數

關鍵字引數,需使用'形參引數名=傳遞引數值'指定好了形參的值,關鍵字引數的順序不需要和形參保持一致,但是如果還有位置引數,需要放在關鍵字引數的前面。

data_print(sex='人妖', hobby='男', age=45) # 我的性別是人妖,年齡是45,愛好是男

(3)混合傳參

既有位置引數,又有關鍵字引數的情況,位置引數一定要在關鍵字引數的前面,否則報錯。

data_print('男', hobby='足球', age=45) # 我的性別是男,年齡是45,愛好是足球

如果位置引數不在關鍵字引數前面,會報錯提示。

data_print(hobby='足球', age=45,'男')
# 報錯
SyntaxError: positional argument follows keyword argument

總結一下實參角度的引數使用,如下。

  1. 位置引數:需要和形參順序一一對應。
  2. 關鍵字引數:順序不一定,但是要一一對應。
  3. 混合引數:位置引數一定要在關鍵字引數的前面。

形參角度(*args **kwargs)

(1)位置引數

形參角度的位置引數同上,練習傳入一個列表,如果列表的長度大於2,那麼僅僅保留前兩個長度的內容返回。

# 不管長度是否大於2,切片都可以使用
def get_list_3(li):
    return li[0:2]

(2)預設引數

可以在形參中定義預設引數,預設引數需要定義在引數後面。

#年齡預設25
def data_print_2(sex, hobby, age=25):
    print('我的性別是%s,年齡是%s,愛好是%s' % (sex, age, hobby))

data_print_2('男', '足球') # 我的性別是男,年齡是25,愛好是足球
# 如果傳入age,則覆蓋預設值
data_print_2('男', '足球', age=45) # 我的性別是男,年齡是45,愛好是足球

(3)*args

args是arguments的簡寫,表示位置引數。使用星號在函式定義時代表聚合,*args代表將可變引數聚合成一個元祖,將結果傳遞給函式實參。

def my_print(*args):
    print(type(args)) 
    print('天皇巨星:%s,%s,%s,%s' % args) 
    
my_print('messi', 'ronald', 'herry', 'kaka')

# 執行結果
# <class 'tuple'>
# 天皇巨星:messi,ronald,herry,kaka

(4)**kwargs

kwargs是keyword arguments的縮寫,表示關鍵字引數。**kwargs是聚合關鍵字引數為一個字典,儲存到kwargs中傳遞給函式實參。

def test(**kwargs):
    print(kwargs)
# 列印結果為字典
test(name='clyang',age=28,hobby='football') # {'name': 'clyang', 'age': 28, 'hobby': 'football'}

使用*args和**kwargs可以接收任意型別的引數。

# 位置引數,被*args接收,關鍵字引數,被**kwargs接收
def func(*args,**kwargs):
    print(args)
    print(kwargs)
# 測試傳入位置引數和關鍵字引數
func(1,2,3,name='messi',age=34,score=33) 

# 輸出結果
# (1, 2, 3)
# {'name': 'messi', 'age': 34, 'score': 33}

形參角度的引數順序

形參角度的引數使用,包括位置引數、預設引數、*args、**kwargs、僅限關鍵字引數。

(1)位置引數、預設引數、args一起使用時,順序為位置引數、args、預設引數。

def sequence(a,b,*args,c='男'):
    print(a,b)
    print(c)
    print(args)

sequence(1,2,3,4,5) 
sequence(1,2,3,4,5,c='人妖')

輸出結果可以看出,a和b分別接收了1和2,*args接收了後面的三個引數3、4、5形成元祖。

1 2
男
(3, 4, 5)

1 2
人妖
(3, 4, 5)

(2)位置引數、預設引數、args、**kwargs一起使用時,順序為位置引數、args、預設引數、**kwargs。

def sequence_2(a,b,*args,c='男',**kwargs):
    print(a, b)
    print(c)
    print(args)
    print(kwargs)

sequence_2(1,2,3,4,5,name='messi',age=28)
sequence_2(1,2,3,4,5,name='messi',age=28,c='女')
sequence_2(1,2,3,4,5,c='人妖',name='messi',age=28)

輸出結果,a和b分別接收了1和2,*args接收了後面的三個引數3、4、5形成元祖,**kwargs接收關鍵字引數形成字典。

1 2
男
(3, 4, 5)
{'name': 'messi', 'age': 28}

1 2
女
(3, 4, 5)
{'name': 'messi', 'age': 28}

1 2
人妖
(3, 4, 5)
{'name': 'messi', 'age': 28}

(3)僅限關鍵字引數

處於*args和**kwargs之間的引數,就是僅限關鍵字引數。

def sequence_3(a,b,*args,c='男',d,**kwargs):
    print(a, b)
    print(c)
    print(d)
    print(args)
    print(kwargs)

sequence_3(1,2,3,4,5,name='messi',age=28,d='僅限關鍵字引數')

輸出結果,a和b分別接收了1和2,*args接收了後面的三個引數3、4、5形成元祖,**kwargs接收關鍵字引數形成字典,d接收'僅限關鍵字引數'。d這個引數位置可以看出,它不可能是位置引數,只能在呼叫的時候賦予值變成僅限關鍵字引數。

1 2
男
僅限關鍵字引數
(3, 4, 5)
{'name': 'messi', 'age': 28}

行參的引數最終順序為:位置引數、*args、預設引數、僅限關鍵字引數、**kwargs,其中預設引數和僅限關鍵字引數位置可以互換。

'*'和'**'

*或**,在函式定義時,代表聚合,而在函式使用時,代表打散。

def func_2(*args):
    print(args)

func_2([1,2],[3,4]) # ([1, 2], [3, 4])
func_2(*[1,2],*[3,4]) # 等效func_2(1, 2, 3, 4),結果為(1, 2, 3, 4)
func_2(1, 2, 3, 4) # (1, 2, 3, 4)

def func_3(**kwargs):
    print(kwargs)

func_3(name='messi',age=28) # {'name': 'messi', 'age': 28}
func_3(**{'name':'messi'},**{'age':28}) # 等效func_3(name='messi',age=28)

函式練習

函式練習主要還是複習前面知識點為主,只是套了一個函式的外殼,體會函式。

(1)寫一個函式,傳入一個字典,判斷字典裡value的長度,如果value長度大於2,只保留前兩個長度的內容,將新的結果返回。

def get_new_dict(dic):
    new_dic = {}
    for key in dic:
        new_dic[key] = dic.get(key)[0:2]
    return new_dic

print(get_new_dict({'name': 'haaaa', 'hobby': 'football', 'score': 'many'})) # {'name': 'ha', 'hobby': 'fo', 'score': 'ma'}

(2)寫一個函式,此函式值接受一個引數並且引數型別必須是列表型別,此函式完成的功能是返回呼叫者一個字典,鍵值對分別是列表元素的索引-元素值,如傳入['messi','ronald','herry','kaka'],返回{1:'messi',2:'ronald',3:'herry',4:'kaka'}。

def get_dict_from_list(li):
    # if type(li) == type([]):
    if isinstance(li, list):
        dic = {}
        for index in range(len(li)):
            dic[index] = li[index]
        return dic
    else:
        return '錯誤的資料型別'


print(get_dict_from_list(['messi', 'ronald', 'herry'])) # {0: 'messi', 1: 'ronald', 2: 'herry'}
print(get_dict_from_list('haha')) # 錯誤的資料型別

(3)寫一個函式,接受四個引數分別是:姓名、性別、年齡、學歷。使用者輸入這個四個內容,傳入到函式後,函式接受到這四個內容,將內容追加到一個檔案中。支援使用者持續輸入,按Q或者q退出,性別預設是男,如果使用者輸入女,則性別更換為女。

def append_to_file(name, age, background, gender='男'):
    with open('student_info.txt', encoding='utf-8', mode='a') as f1:
        f1.write('{}\t{}\t{}\t{}\n'.format(name, gender, age, background))


while 1:
    str = input('請輸入姓名,性別,年齡,學歷,按空格隔開')
    if str.upper() == 'Q': break
    if len(str.split()) != 4:
        print('輸入資訊不是4個')
    else:
        li = str.split()
        if li[2].isdecimal():
            name = li[0]
            gender = li[1]
            age = int(li[2])
            background = li[3]
            # 呼叫函式
            if gender == '女':
                append_to_file(name, age, background, gender)
            else:
                append_to_file(name, age, background)
        else:
            print('輸入年齡格式錯誤,請重新全部輸入')

(4)寫函式,使用者傳入修改的檔名,與要修改的內容,執行函式完成整個檔案批量的修改操作。

import os
def modify_file(filepath,old,new):
    with open(filepath, encoding='utf-8', mode='r') as f1, \
            open(filepath+'_bak', encoding='utf-8', mode='w') as f2:
        for line in f1:
            # 讀一行,修改一行
            new_line=line.replace(old,new)
            # 修改一行,寫一行
            f2.write(new_line)
    # 刪除舊檔案
    os.remove(filepath)
    # 重新命名新檔案
    os.rename(filepath+'_bak',filepath)

modify_file('檔案的修改.txt','clyang','超哥')

PS:以上,理解不一定正確,學習就是一個不斷認識和糾錯的過程,如果有誤還請批評指正。

參考博文:

(1)https://www.jianshu.com/p/0ed914608a2c *args **kwargs

(2)https://www.cnblogs.com/scofi/p/4920989.html 位置引數