1. 程式人生 > >Python3.6基礎知識 函式 引數【四】

Python3.6基礎知識 函式 引數【四】

Python函式

函式

函式是一個特定功能的結構,屬於程式碼組的一種

函式的特徵

  • 函式的定義必須使用def關鍵字
  • 函式的命名規則
    • 不允許使用中文,儘量使用英文
    • 可以包含數字,但是不能以數字開頭
    • 不可以使用特殊符號,_除外
    • 函式名嚴格區分大小寫
    • 函式名不要與關鍵字衝突
    • 函式名要見其名知其意
  • 函式不被呼叫不被執行

函式的定義

定義函式的規則

  • def關鍵字開頭 ,後跟一個空格
  • 函式名後接括號,括號內可有引數可無引數,括號後接冒號
  • 函式內所有程式碼縮排
  • 編寫函式文件,可以不寫,但是作為一個合格的程式猿,強烈推薦編寫
  • 編寫函式體
  • 使用return返回,這個可以不寫,Python預設會返回

如下函式

def printName() :
    print('定義了一個函式')
    print('王小兒')

這需要呼叫才會執行
在這裡插入圖片描述


函式的引數

引數的分類

  • 位置引數
    • 定義的時候直接定義變數名,也就是形參名
    • 呼叫的時候直接把變數名與值按位置一一對應放入即可,不傳引數是不合法的
  • 預設引數
    • 形參帶有預設值
    • 呼叫的時候如果沒有傳入值,則使用預設值
  • 關鍵字引數
  • 收集引數

位置引數

這種引數也是最普遍的,需要幾個引數就定義幾個,只定義形參名稱,然後呼叫的時候按對應的形參位置傳入值就行了

def hello(name) :
    print('{0},你怎麼了'.format(name))

def hello2(name,name2):
    print(name,name2)

def hello3(name,name2,name3):
    print(name,name2,name3)

hello('ya')
hello2('ya','wa')
hello3('ya','wa','aa')

這裡切記傳參一定要與形參位置對應,且必須傳,不能少

預設引數

這裡就是形參有預設值

def helloMan(name='王二'):
    print('{0},早上好啊'.format(name))

def helloM(n1='w',n2='q'):
    print(n1,n2)

helloMan('xiao')
helloM()

這種引數就是引數可傳可不傳

如果位置引數與預設引數都有的話,切記所有位置引數必須出現在預設引數前,包括函式定義和呼叫

def print_hello(n1,n2,n3='op'):
    print(n1,n2,n3)
    
print_hello('1','2')
print_hello('1','2','oo')

關鍵字引數

這種引數在定義方法定義確定形參階段跟預設引數和位置引數是一樣的,只是在呼叫階段不一樣

呼叫的時候,以鍵值對的形式指定引數名和引數值,這樣做雖然麻煩,但是不容易出現位置混淆

def helloM(n1,n2='2'):
    print(n1,n2)
def helloMe(n1='1',n2='2'):
    print(n1,n2)
def print_hello(n1,n2,n3='op'):
    print(n1,n2,n3)

helloM('1',n2='2')
helloMe(n1='3')
helloMe(n1='3',n2='2')
print_hello(1,2,n3='4')

//這種就是錯誤的呼叫
print_hello(1,n3='4',2)

但是呼叫的時候一定要注意,有位置引數,位置引數一定要在關鍵字引數前面;關鍵字引數之間不存在先後順序

收集引數

定義函式時,有時候我們不確定呼叫的時候到底會傳遞幾個引數(不傳也可以),此時,可用包裹(packing)位置引數,或者包裹關鍵字引數,來進行引數傳遞,會顯得非常方便

包裹位置引數

def hello_p(*arg):
    print(arg)
    print(arg[0])

hello_p(1,2,3)

列印結果

(1, 2, 3)
1

我們傳進的所有引數都會被arg變數收集,它會根據傳進引數的位置合併為一個元組(tuple),args是元組型別,這就是包裹位置傳遞

注意:形參名之前新增*

包裹關鍵字引數

def func(**arg):
    print(arg)
    
func(a=1,b=2)

列印結果

{‘a’: 1, ‘b’: 2}

arg是一個字典(dict),收集所有關鍵字引數

注意:形參名之前新增**

引數混合使用

基本原則是:先位置引數,預設引數,包裹位置引數,關鍵字引數,包裹關鍵字引數(定義和呼叫都應遵循)

def func(name, age, sex=1, *args, wife='ya',**kargs):
    print(name,age,sex,args,wife,kargs)
    
func('ming',22,0,11,2,1,3,wife='ai',h=175,w=70)

列印結果

ming 22 0 (11, 2, 1, 3) ai {‘h’: 175, ‘w’: 70}


函式的返回值

Python中也是使用return這個關鍵字作為函式的返回的,但是這裡的函式不像Java或者其它語言,需要在定義函式的時候在方法名前面定義好返回值型別;Python中直接像上面那樣定義方法,然後需要返回就直接return就行了

def helloMen(persion):
    return '{0},你怎麼不理我啊{1}'.format(persion,persion)

在這裡插入圖片描述

注意:這裡如果我們沒有return,那這裡的result是None,也就是說函式中沒有return的話,也會返回一個值,只不過是None


變數作用域

在函式中宣告變數的有效使用範圍就是函式的變數作用域

分類

  • 全域性變數:在函式外宣告的變數就是全域性變數,作用域是整個程式
  • 區域性變數:在函式內部宣告的變數就是區域性變數,作用域是函式內

注意:如果全域性變數和區域性變數同名時,在定義區域性變數的函式內,區域性變數有效,其餘地方全域性變數有效

name = 'xiao wamg' # 全域性變數

def funcname():
    value = 'this' # 區域性變數
    name = 'lao er' # 區域性變數
    print('name:',name)

我們來呼叫下

funcname()

看看結果

name: lao er

global關鍵字

這個關鍵字幹嘛的呢,其實看這個單詞的意思應該知道了,它是將區域性變數變成全域性變數

def pri():
    print(na)
    
def name():
    global na  # 升級成全域性變數
    na = 'wang er'
    print('我定義了一個全域性變數')

可以看到在第二個方法中定義了一個變數,但是前面加了一個global修飾,注意,python中有關鍵字修飾的變數一定要先定義,再賦值,千萬別global na = ‘wang er’ 這種寫法
接下來呼叫

name()
pri()

列印結果

我定義了一個全域性變數
wang er

這裡可以看到第一個方法也能用到這個變量了

注意:雖然這樣做可以,但是要記住方法只有呼叫了才會執行,也就是說第一個方法要能用這個變數,前提是第二個方法要先呼叫,讓這個變數生效


檢視函式文件

比我我們想檢視print函式的官方解釋,也就是函式文件了,怎麼辦呢,如下

help(print)

就是使用help函式,然後把函式名作為引數傳進去

看看打印出來的結果

Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

我們重點看第三局

print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

第一個value也就是我們傳的引數,
後面的…就是表示可以傳多個引數,
再後面的sep=’ ‘,看下面的解釋,說處於兩個引數之前的string,也就是以這個分割多個引數,預設是空格
再後面的end=’\n’,也就是以什麼結束,預設是\n,這個轉義字元,意思就是換行;多個引數並不會在同一行打印出來

我們接下來用一個九九乘法表舉例

for row in range(1,10):
    for col in range(1,row+1):
        if col == 1 :
            print('第{0}行'.format(row),col * row,sep=' ',end=' ')
        else :
            print(col * row,end=' ')
    print('----')

看看執行結果
在這裡插入圖片描述

自定義函式文件

假如我們要對自己定義的函式寫函式文件怎麼辦呢?

方法:在函式內部開始的第一行使用字串定義文字內容即可或者使用… …將內容包括起來

在這裡插入圖片描述

在這裡插入圖片描述

內部函式

這個其實就是在函式內部宣告的函式就是內部函式,這也是函式巢狀

  • 內部函式在函式內部可以訪問
  • 內部函式的呼叫必須在定義內部函式之後
  • 內部函式不可以在函式外部呼叫
  • 本質上內部函式等同於內部變數

nonlocal關鍵字

nonlocal的作用是聲明當前變數不是當前內部函式中的變數,他有可能是當前函式的外部變數(不是全域性變數)

def foo():
    name='lhf'
    def bar():
        nonlocal age #聲明當前變數不是內部函式中的變數
        print(name)

遞迴函式

如果一個函式在內部呼叫自己,那這個函式就是遞迴函式

  • 遞迴函式必須要有一個明確的結束條件,不能無限遞迴
  • Python中對遞迴層次有限制,超過限制會報錯
  • 遞迴層次過多會導致棧溢位(在計算機中,函式呼叫是通過棧(stack)這種資料結構實現的,每當進入一個函式呼叫,棧就會加一層棧幀,每當函式返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞迴呼叫的次數過多,會導致棧溢位)

在Python中進行遞迴不像Java或者其它語言,沒做限制,能無限遞迴,頂多把機器搞崩;但是在Python中不行,有遞迴次數有限制

具體遞迴什麼樣呢,看程式碼

def calc(num):
    print(num)
    if int(num/2) == 0 :
        return num
    else :
        calc(int(num/2))

接下來呼叫下

result = calc(8)

看結果

8
4
2
1