函式基本使用
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歲了