一、函數的定義python
二、如何使用函數程序員
三、函數的返回值編程
四、使用註釋改進文檔數據結構
五、傳遞任意數量的實參app
六、函數與模塊編程語言
函數的通常定義(中學/數學):函數的近代定義是給定一個數集A,假設其中的元素爲x,對A中的元素x施加對應法則f,記做f(x),獲得另外一數集B,假設B中的元素爲y,則y與x之間的等量關係能夠用y=f(x)表示,函數概念含有三個要素:定義域A、值域C和對應法則f。ide
編程語言中函數的定義(計算機):函數是邏輯結構化和過程化的一種編程方法。函數
函數的定義方法(案例):oop
>>> def fib(n): # write Fibonacci series up to n ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while a < n: ... print(a, end=' ') ... a, b = b, a+b ... print() """ def:定義函數的關鍵字 flb:函數名 (n):定義函數的參數 """""":文檔描述 代碼塊: a, b = 0, 1 while a < n: print(a, end=' ') a, b = b, a+b print() """
具體學習:學習
下面打印一個問候的簡單函數:
1 def greet_user(): #定義一個函數,關鍵詞爲"def",函數名爲"greet_user",最後以「:」結尾 2 """顯示簡單的問候語""" #描述函數的具體功能 3 print("Hello!") #函數體的代碼塊,用於實現函數功能 4 5 greet_user() #調用函數
注意:(1)在第一行定義函數中,不須要任何信息就能完成工做,所以括號是空的(即使如此,括號必不可少!)
(2)要調用函數,能夠依次指定函數名以及括號括起的必要信息。在第五行代碼中,由於此函數greet_uesr()括號中不須要任何信息,只須要輸入greet_uesr()便可。和預期效果同樣,打印Hello!:
練習:大腦P149
1 def search4vowels(): 2 vowels = set('aeiou') 3 word = input("Provide a word to search for vowels:") 4 found = vowels.intersection(set(word)) 5 for vowel in found: 6 print(vowel) 7 8 search4vowels() 9 search4vowels() #能夠重複屢次調用
函數的使用方法(先看案例)
>>> def fib2(n): # return Fibonacci series up to n ... """Return a list containing the Fibonacci series up to n.""" ... result = [] ... a, b = 0, 1 ... while a < n: ... result.append(a) # see below ... a, b = b, a+b ... return result ... >>> f100 = fib2(100) # call it >>> f100 # write the result [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
針對greet_user()只要稍做修改,就可不只實現Hello,還能夠將用戶名字做爲擡頭:
1 def greet_user(username): 2 """顯示簡單的問候語""" 3 print("hello,"+username.title()+"!") 4 5 greet_user("zhichao")
代碼greet_user("zhichao")調用函數greet_user()時,向它傳遞執行print()語句所須要的信息username。
greet_user(username) #username 爲形參;函數完成其工做時所須要的信息。
greet_user("zhichao") #"zhichao"爲實參;實參是調用函數時傳遞給函數的信息。
形參:形式參數,不是實際存在的,是虛擬變量。在定義函數和函數體的時候使用形參,目的是在函數調用時接收實參
實參:實際參數,調用函數時傳遞給函數的參數,能夠是常量、變量,表達式,函數,傳給形參
區別:形參是虛擬的,不佔用空間,形參變量只有在被調用時才分配內存單元,實參是一個變量,佔用內存空間,數據傳遞單向,實參傳給形參,不能倒過來。
傳遞實參:
一、位置實參(基於實參的順序):
1 #zhichao 2 3 def describe_pet(animal_type,pet_name): 4 """顯示寵物信息""" 5 print("\nI have a" + animal_type + ".") 6 print("My" + animal_type + "'s name is "+pet_name.title() + ".") 7 8 describe_pet('hamster','harry') 9 describe_pet('cat','python') #函數調用屢次是一種效率極高的工做方式
位置實參的順序很重要,請確認函數調用中實參的順序與函數定義形參的順序一致
2 關鍵字參數
1 def describe_pet(pet_name,animal_type="dog",): 2 """顯示寵物信息""" 3 print("\nI have a " + animal_type + ".") 4 print("My" + animal_type + "'s name is "+pet_name.title() + ".") 5 6 describe_pet(pet_name='harry',animal_type='hamster') #關鍵字實參 7 describe_pet(pet_name='python',animal_type='cat') #關鍵字實參
思考1:關鍵字參數是否須要與形參順序一致?
思考2:關鍵字參數和位置參數可否同時存在?
例:
#eg1 def func_test(x,y): print(x) print(y) func_test(x=1,2) #? #eg2 def func_test(x,y): print(x) print(y) func_test(1,y=2) #? #eg3 def func_test(x,y,z): print(x) print(y) func_test(1,y=2,3) #? #結論?
****關鍵參數是不能夠寫在位置參數前面的
編寫函數時,能夠給形參指定默認值。
1 def describe_pet(pet_name,animal_type="dog",): 2 """顯示寵物信息""" 3 print("\nI have a " + animal_type + ".") 4 print("My" + animal_type + "'s name is "+pet_name.title() + ".") 5 6 describe_pet('harry','hamster') 7 describe_pet('python','cat')
eg:
1 #Zhichao 2 3 def greet_users(names): 4 """向列表中的每位用戶都發出簡單的問候""" 5 for name in names: 6 msg = "Hello, "+name.title() +"!" 7 print(msg) 8 9 usernames = ['hannah','ty','margot'] 10 greet_users(usernames)
函數返回的值被稱爲函數的返回值;
在函數中,可用return語句將值返回到調用函數的代碼行;
返回值能將你程序的大部分繁重工做移到函數中去完成,從而簡化主程序。
eg(formatted_name1):
1 #zhichao 2 3 def get_formatted_name(first_name,last_name): 4 """返回整潔的姓名""" 5 full_name = first_name + ' '+ last_name 6 return full_name.title() 7 8 musician = get_formatted_name('jimi','hendrix') #調用返回值的函數時,須要提供一個變量,用於存儲返回的值 9 print(musician)
有時候,須要讓實參變成可選的,這樣使用函數的人就只須要在必要時候才提供額外信息。
咱們對:formatted_name1 進行擴展(函數的可擴展性)
eg(formatted_name2):
1 def get_formatted_name(first_name,middle_name,last_name): 2 """返回整潔的姓名""" 3 full_name = first_name + ' '+middle_name+' '+ last_name 4 return full_name.title() 5 6 musician = get_formatted_name('jimi','lee','hendrix') #有些人有中間名 7 print(musician)
有些人不必定有中間名,那麼對函數進行優化:
eg(formatted_name2):
#zhichao def get_formatted_name(first_name,last_name,middle_name=''): #複習關鍵字實參放後面 """返回整潔的姓名""" if middle_name: full_name = first_name + ' '+middle_name+' '+ last_name else: full_name = first_name + ' ' + last_name return full_name.title() musician = get_formatted_name('jimi','lee','hendrix') musician1 = get_formatted_name('jimi','hendrix') print(musician) print(musician1)
函數能夠返回任意類型的值,包括列表、字典和集合等較爲複雜的數據結構。
大腦P159:
返回一個值:
返回一個集合:
1 # Zhichao 2 3 def search4vowels(word): 4 """Return a boolean based on any vowels found""" 5 vowels = set('aeiou') 6 found = vowels.intersection(set(word)) 7 return found 8 word = search4vowels('hello Zhichao') 9 print(word)
返回數據:
1 #Zhichao 2 3 def search4vowels(word): 4 """Return a boolean based on any vowels found""" 5 vowels = set('aeiou') 6 return vowels.intersection(set(word)) 7 word = search4vowels('hello Zhichao') 8 print(word)
返回字典:
1 #Zhichao 2 3 def build_person(first_name,last_name): 4 """返回一個字典,其中包含有關一我的的信息""" 5 person = {'first':first_name,'last':last_name} 6 return person 7 8 musician = build_person('jimi','hendrix') 9 print(musician)
複習python的四種數據類型。
當咱們調用函數時,才知道咱們須要輸入的參數和返回值的類型「type」
對此,咱們的一種解決辦法是把這個信息增長到docstring
python3 註解的記法
1.函數註解是可選的。
2.函數註解能夠提供信息。
eg:
1 #zhichao 2 3 def search4vowels(word:str) ->set: 4 """Return a boolean based on any vowels found""" 5 vowels = set('aeiou') 6 return vowels.intersection(set(word)) 7 8 help(search4vowels)
1. *args,傳入多個參數,轉化成元組。
假如一個函數定義一個披薩的配料,但並不知道有多少配料須要加入,在參數不肯定的狀況下,咱們引入任意數量的實參。
eg:
#Zhichao def make_pizza(*toppings): """打印顧客點的全部配料""" print(toopings) make_pizza("peperoni") make_pizza("mushroom","green peppers","extra cheese")
注意:*toppings的值是一個封裝好的空元組,並將全部接收到的值都封裝在這個元組裏。
2.**kwargs,把關鍵字參數,轉化成字典。
eg:
1 # -*- coding:utf-8 -*- 2 # Author:Zhichao 3 4 def infos(**kwargs): 5 """打印我的信息""" 6 print(kwargs) 7 8 infos(name="Zhichao",age="24",job="IT")
設計一個對顧客點披薩進行描述:
1 #Zhichao 2 3 def make_pizza(*toopings): 4 """概述要製做的披薩""" 5 print("\nMaking a pizza with the following toppings") 6 for topping in toopings: 7 print("--"+topping) 8 9 make_pizza("peperoni") 10 make_pizza("mushroom","green peppers","extra cheese")
結合位置實參和任意數量實參:
#Zhichao def make_pizza(size,*toopings): #回顧位置實參應放在前面 """概述要製做的披薩""" print("\nMaking a "+str(size)+"-inch pizza with the following toppings") for topping in toopings: print("--"+topping) make_pizza(14,"peperoni") make_pizza(12,"mushroom","green peppers","extra cheese")
函數的優勢之一是將代碼與主程序分離;
咱們能夠更進一步,將函數存儲在被稱爲「模塊」的獨立文件中,再將模塊導入主程序;
import語句容許咱們在當前運行的程序文件中使用模塊中的代碼。
優點:
1.經過將函數存儲在獨立的文件中,可隱藏程序代碼的細節,將重點放在程序的高層邏輯上;
2.可讓不一樣的程序中重用函數;
3.可與其餘程序員共享這些文件而不是整個程序;
4.知道如何導入函數能讓你使用其餘程序員編寫的函數庫。
模塊是擴展名爲.py的文件(如一些內置的模塊:C:\ProgramData\Anaconda3\Lib)
下面咱們來建立一個模包含函數make_pizza()的模塊。
pizza.py
1 #Zhichao 2 3 def make_pizza(size,*toopings): 4 """概述要製做的披薩""" 5 print("\nMaking a "+str(size)+"-inch pizza with the following toppings") 6 for topping in toopings: 7 print("--"+topping)
接下來,咱們在pizza.py所在目錄下建立一個另外的名爲making_pizzas.py文件,這個文件導入剛建立的模塊,在調用make_pizza()兩次:
making_pizzas.py
1 import pizza #調用模塊 2 3 pizza.make_pizza(16,'pepperoni') #調用模塊的函數 4 pizza.make_pizza(12,"mushroom","green peppers","extra cheese")
能夠導入模塊中的特定函數,方法以下:
1 from module_name import function_name
經過用逗號分開函數名能夠同時導入多個函數:
1 from module_name import function_0,function_1,function_2
對於前面的pizza案例,咱們能夠導入模塊中的特定函數:
1 from pizza import make_pizza 2 make_pizza(16,'pepperoni') #調用模塊的函數 3 make_pizza(12,"mushroom","green peppers","extra cheese")
若使用此種方法,調用函數時不須要用句點。
思考:若是你導入的函數名與程序中現有的名稱衝突怎麼辦?或者你調用的函數名稱太長怎麼辦?
咱們能夠指定函數的另外一個名稱,相似於外號。
下面咱們根據make_pizza指定名稱
1 from pizza import make_pizza as mp 2 mp(16,'pepperoni') #調用模塊的函數 3 mp(12,"mushroom","green peppers","extra cheese")
通用語法格式:
1 from moudle_name import function_name as fn
eg:
1 import pizza as p 2 3 p.make_pizza(16,'pepperoni') 4 p.make_pizza(12,"mushroom","green peppers","extra cheese")
通用語法格式:
import moudle_name as mn
使用星號(*)運算符可讓Python導入模塊中的全部函數:
1 #Zhichao 2 from pizza import* 3 4 make_pizza(16,'pepperoni') 5 make_pizza(12,"mushroom","green peppers","extra cheese")
通用語法格式:
from moudle_name import *
大腦P162
使用註解改進文檔:
關於註解更多詳細內容參見PEP3107
(https://www.python.org/dev/peps/pep-3107)
大腦 P164
函數:咱們已經知道些什麼
* 函數是命名的代碼塊。
* def關鍵字用來命名函數,函數代碼在def關鍵字下(相對於def關鍵字)縮進
* Python的三重引號字符串能夠用來函數增長多行註釋。若是採用這種方式,他們稱之爲docstring
* 函數能夠接受任意多個命名參數
* return語句容許函數返回任意值(也能夠不反回任何值)
*函數註解能夠用來描述函數參數的類型
創建一個通用的函數:
1 #Zhichao 2 3 def search4vowels(phrase: str) -> set: 4 """return any vowels found in a supplied phrase""" 5 vowels = set('aeiou') 6 return vowels.intersection(set(phrase)) 7 8 def search4letters(phrase:str,letters:str)->set: 9 """return a set of the 'letters' found in 'phrase'. """ 10 return set(letters).intersection(set(phrase)) 11 12 help(search4letters) 13 print(search4letters('hitch-hiker','aeiou')) 14 print(search4letters('galaxy','xyz'))
函數能夠調用函數嗎?
函數引用
eg:
1 # Author:Zhixhao 2 3 def search4letters(phrase:str,letters:str)->set: 4 """return a set of the 'letters' found in 'phrase'. """ 5 logger("search4letters") 6 return set(letters).intersection(set(phrase)) 7 8 def logger(source): 9 print("from %s"%source) 10 help(search4letters) 11 12 print(search4letters('hitch-hiker','aeiou')) 13 print(search4letters('galaxy','xyz'))
局部變量與全局變量以及其做用域:
1 #Zhichao 2 3 school = "中山大學" 4 5 def change_name(name:str): 6 """修更名字""" 7 # global school 8 school = "中山大學南方學院" 9 print("before change",name,school) 10 name = name.title() #局部變量,能夠理解這個函數就是這個變量的做用域 11 # age = 18 12 print("after change",name) 13 14 # print("age",age) 15 name = "zhichao" 16 change_name(name) 17 print(name,school)
不建議使用 global 在函數內部修改全局變量,容易致使邏輯混亂不清
再來看一個例子:
1 # Author:Zhichao 2 3 names = ["Marry","Jack","Lin"] 4 def change_name(): 5 names.append("Zhichao") 6 print("inside func",names) 7 8 change_name() 9 print(names)
請閱讀大腦P185-p187
並嘗試理解:
總結:
可變:列表、字典和集合
不可變:字符串、整數和元組
(回顧字典的key命名)
1 def calc(n): 2 print(n) 3 if int(n/2) == 0: 4 return n 5 return calc(int(n/2)) 6 7 calc(10)
遞歸特性:
1.必須有一個明確的結束條件
2.每次進入更深一層遞歸時,問題規模相比上次遞歸應有所減小。
3.遞歸效率不高,遞歸次數過多會致使棧溢出(在計算機中,函數調用是經過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會多加一層棧幀,每當函數返回,棧就會減小一層棧幀。因爲棧的大小不是無限的,因此,遞歸調用的次數過多,會致使棧溢出。)