Python基礎-函式

不該相遇在秋天發表於2020-07-08

函式基本使用

python中定義函式所用的關鍵字是def, def 函式名() : 冒號代替其他程式語言的大括號,然後換行縮排寫的程式碼就是函式體。

def welcome():
    '''
    一個簡單的函式
    :return:
    '''
    print("Hello World !")


welcome()

列印結果:

Hello World !

 

三引號中間的內容屬於函式的註釋文件,在實際專案中都儘量要把每個函式的文件註釋寫好,在這裡為了節約篇幅,本文下面的程式碼示例就不再新增這個註釋了。

 

函式還可以巢狀,也就是函式裡面有函式:

def welcome(name):
    def go(name):
        print('我最棒:' + name)
    go(name)

welcome('小明')

列印結果:

我最棒:小明

 

函式的引數

形參和實參

def welcome(username):
    print("Hello World ! My name is " + str(username))

welcome("小明")
welcome("小花")

列印結果:

Hello World ! My name is 小明
Hello World ! My name is 小花

這是一個帶引數的函式,在函式welcome中,username就是一個形參,也就是形式引數,是用來接收呼叫函式時傳入的引數,你傳的是啥它就是啥,傳人它就是人,傳鬼它就是鬼的那種。

實參就是實際引數,在呼叫函式的時候,傳遞是小明,那麼小明就是實參,傳遞的是小花,那麼小花也是實參,實參傳遞給函式後,會賦值給函式中的形參,然後我們就可以在函式中使用到外部傳入的資料了。

 

引數預設值

寫Java的時候最痛恨的就是方法不能設定預設值,使得必須得過載才行。

python允許我們給函式的形參設定一個預設值,不傳引數呼叫的話,就統一預設是這個值。

def welcome(username = '奧特曼'):
    print("Hello World ! My name is " + str(username))

welcome("小明")
welcome()

列印結果:

Hello World ! My name is 小明
Hello World ! My name is 奧特曼

 

修改引數後影響外部

在函式中修改引數內容會不會影響到外部,這個問題取決於實參的型別是不是可變的,可不可變就是可不可以修改。

 

字串就是一種不可變的型別。

比如:

name = "小明"
name = "小花"

請問,我是把"小明"修改成了"小花"嗎? 答案是 非也。

實際上我是把"小花"這個字串賦值給了name,讓name指向了這個新字串,替換掉了原來的"小明",原來的"小明"仍然是"小明",沒有受到一點改變。

在python中,不可變型別有:整數、字串、元組,可變型別有:列表、字典。如果傳遞的引數包含可變型別,並且在函式中對引數進行了修改,那麼就會影響到外部的值

def change(lis):
    lis[1] = '小明他大爺'

names = ['小明','小花','小紅']
change(names)
print(names)

列印結果:

['小明', '小明他大爺', '小紅']

 

如果我們不希望出現這種事情,那麼就將物件複製一份再傳遞給函式。

def change(lis):
    lis[1] = '小明他大爺'

names = ['小明','小花','小紅']
change(names[:])
print(names)

列印結果:

['小明', '小花', '小紅']

我們用切片的方法拷貝了一份names,函式中儘管修改了引數,也不過是修改的是副本,不會影響到原始的names。

 

關鍵字引數

關鍵字引數讓你可以不用考慮函式的引數位置,你需以鍵值對的形式指定引數的對應形參。

def welcome(name,address):
    print(f"你好 {name} , 歡迎來到 {address} !")

welcome(address='上海',name='小強')

列印結果:

你好 小強 , 歡迎來到 上海 !

 

收集引數

有時候我們需要允許使用者提供任意數量的引數,函式的形參可以帶個星號來接收,不管呼叫函式的時候傳遞了多少實參,都將被收集到形參這個變數當中,形參的型別是元組。

def welcome(*names):
    print(names)

welcome('小明','小強','小紅','小黑')

列印結果:

('小明', '小強', '小紅', '小黑')

 

還有一種是帶兩個星號的形參,用於接收鍵值對形式的實參,匯入到函式中的型別是字典。

def welcome(**names):
    print(names)

welcome(name='小明',age=18,sex='')

列印結果:

{'name': '小明', 'age': 18, 'sex': '男'}

 

分配引數

分配引數是收集引數的相反操作,可使得一個元組或字典變數自動分配給函式中的形參。

def welcome(name,address):
    print(f"你好 {name} , 歡迎來到 {address} !")

a = ('小紅','山東')
welcome(*a)

列印結果:

你好 小紅 , 歡迎來到 山東 !

 

我們改成字典的方式:

def welcome(name,address):
    print(f"你好 {name} , 歡迎來到 {address} !")

a = {'address':'山東','name':'小紅'}
welcome(**a)

列印結果:

你好 小紅 , 歡迎來到 山東 !

 

函式的返回值

首先說明,所有的函式都是有返回值的,如果程式設計人員沒有指定返回值,那麼預設會返回None,對標其他語言中的null

一個簡單的函式返回值的例子:

def get_full_name(first_name,last_name):
    return first_name + last_name

r = get_full_name('','大錘')
print(r)

列印結果:

王大錘

 

然而python中的函式還可以返回多個值,返回出的值被裝載到元組中:

def func(num):
    return num**2,num**3,num**4

result = func(2)
print(result)

列印結果:

(4, 8, 16)

 

在python中函式定義的時候沒有返回值的簽名,導致我們無法提前知道函式的返回值是什麼型別,返回的什麼完全看函式中的return的是什麼,特別是邏輯程式碼比較多的函式,比如裡面有多個if判斷,有可能這個判斷return出來的是布林值,另一個判斷return出來的是列表,還一個判斷啥也不return,你呼叫的時候你都搞不清楚該怎麼處理這個函式的返回值,在這一點來說,Java完勝。

 

所以在無規則限制的情況下,程式碼寫的健不健壯,好不好用,主要取決於程式設計人員的素質。

 

匿名函式

匿名函式就是不用走正常函式定義的流程,可以直接定義一個簡單的函式並把函式本身賦值給一個變數,使得這個變數可以像函式一樣被呼叫,在python中可以用lambda關鍵字來申明定義一個匿名函式。

我們把王大錘的例子改一下:

get_full_name = lambda first_name,last_name : first_name + last_name
r = get_full_name('','大錘')
print(r)

列印結果:

王大錘

 

函式的作用域

訪問全域性作用域

python每呼叫一個函式,都會建立一個新名稱空間,也就是區域性名稱空間,函式中的變數就叫做區域性變數,與外部的全域性名稱空間不會相互干擾。

這是常規狀態,當然也會有非常規需求的時候,所以python給我們提供了globals()函式,讓我們可以在區域性作用域中訪問到全域性的變數。

def func():
    a = globals()
    print(a['name'])

name = '小明'
func()

列印結果:

小明

 

globals()函式只能讓我們訪問到全域性變數,但是是無法進行修改的,如果我們要修改全域性變數,需要用到global關鍵字將全域性變數引入進來。

def func():
    global name
    name = '小花'

name = '小明'
func()
print(name)

列印結果:

小花

 

訪問巢狀作用域

對於巢狀函式的情況,如果想要使用巢狀作用域(非全域性作用域)的變數,就需要用到nonlocal關鍵字。

def welcome(name):
    def go():
        nonlocal name
        name = '我變成小花了'
    go()
    print(name)

my_name = '小明'
welcome(my_name)
print(my_name)

列印結果:

我變成小花了
小明

 

函式與模組

匯入模組

模組的官方定義是包含函式和變數的python檔案就叫做模組,然而你照著這個定義去看,你會發現只要是.py的檔案,其實都符合模組的定義。

我新建一個user.py檔案 他也叫做user模組 裡面寫兩個函式

def get_name():
    print('我的名字是小明')

def get_age():
    print('我今年11歲了')

 

然後我用import匯入這個user模組 並呼叫模組中的函式

import user
user.get_name()

列印結果:

我的名字是小明

 

這個用處相當於公共函式的封裝,當然了,我們物件導向的做法一般都是封裝到類裡面。

 

為了防止模組名字被當前程式的變數覆蓋,你可以選擇匯入的時候用as指定別名:

import user as model_user
model_user.get_name()

列印結果:

我的名字是小明

 

匯入函式

還是拿上面user模組來做例子  我現在只匯入其中某個函式

from user import get_name
get_name()

列印結果:

我的名字是小明

 

from ... import ... 的意思就是 從...中獲取...,從user模組中獲取get_name函式。

 

匯入模組中所有函式

萬用字元星號表示匯入所有函式,只是這種做法,有大機率出現函式被覆蓋的風險

from user import *
get_name()
get_age()

列印結果:

我的名字是小明
我今年11歲了

 

相關文章