函數(shù)的定義與使用
函數(shù)的理解與定義
一段代碼的表示
- 一段具有特定功能、可重用的語(yǔ)句組
- 一種功能的抽象,一般函數(shù)表達(dá)特定功能
- 降低編程難度和代碼復(fù)用
def <函數(shù)名>(0個(gè)或多個(gè)參數(shù)):
<函數(shù)體>
return <返回值>
案例:計(jì)算n!
def fact(n):
s = 1
for i in range(1,n+1):
s *= i
return s
- 函數(shù)定義時(shí),所給的參數(shù)是一種占位符
- 函數(shù)定義后,如果不進(jìn)行調(diào)用,不會(huì)被執(zhí)行
- 函數(shù)是IPO的一種實(shí)現(xiàn)和完整代碼的封裝
函數(shù)的使用及調(diào)用過(guò)程
調(diào)用是運(yùn)行函數(shù)代碼的方式
a = fact(10)
print(a)
- 調(diào)用時(shí)要給出實(shí)際參數(shù)
- 實(shí)際參數(shù)替換函數(shù)中的參數(shù)
- 運(yùn)行函數(shù)后得到返回值
函數(shù)的參數(shù)傳遞
函數(shù)可以有參數(shù),也可以沒有,但必須保留括號(hào)
函數(shù)定義是可以為某些參數(shù)指定默認(rèn)值,構(gòu)成可選參數(shù):
def <函數(shù)名>(<非可選參數(shù)>,<可選參數(shù)>):
<函數(shù)體>
return <返回值>
案例:計(jì)算n!//m
def fact(n, m=1):
s = 1
for i in range(1,n+1):
s *= i
return s//m
可變參數(shù)傳遞
函數(shù)定義時(shí)可以設(shè)計(jì)可變數(shù)量參數(shù),即不確定參數(shù)總數(shù)量
def <函數(shù)名>(<參數(shù)>, *b):
<函數(shù)體>
return <返回值>
b是參數(shù)名
案例:計(jì)算n!乘數(shù)
def fact(n, *b):
s = 1
for i in range(1,n+1):
s *= i
for item in b:
s *= item
return s
參數(shù)傳遞的兩種方式
函數(shù)調(diào)用時(shí),參數(shù)可以按照位置或名稱方式傳遞
def fact(n, m=1):
s = 1
for i in range(1,n+1):
s *= i
return s//m
>>> fact(10,5)
725760
也可以帶上名稱
>>> fact9m=5, n=10)
725760
函數(shù)的返回值
可以返回0個(gè)或多個(gè)結(jié)果
-
return保留字用來(lái)傳遞返回值 - 函數(shù)可以有返回值,也可以沒有,可以有
return,也可以沒有 -
return可以返回0個(gè)或多個(gè)值
案例:
def fact(n, m=1):
s = 1
for i in range(1,n+1):
s *= i
return s//m, n, m
返回的是元組類型
>>> fact(10,5)
(725760, 10, 5)
>>> a,b,c = fact(10,5)
>>>print(a,b,c)
725760 10 5
局部變量和全局變量
局部變量:函數(shù)內(nèi)部使用的變量
全局變量:整個(gè)程序使用的變量
規(guī)則1:局部變量和全局變量是不同的變量
- 局部變量是函數(shù)內(nèi)部的占位符,與全局變量可能重名但不同
- 函數(shù)運(yùn)算結(jié)束后,局部變量被釋放
- 可以使用
global保留字在函數(shù)內(nèi)部使用全局變量
n, s = 10, 100
def fact(n):
s = 1 #此處s是局部變量,與全局變量s不同
for i in range(1,n+1):
s *= i
return s #此處s是局部變量,值為3628800
print(fact(n), s) #此處s是全局變量,值為100
使用global保留字:
n, s = 10, 100
def fact(n):
global s #聲明此處的s為全局變量s
s = 1
for i in range(1,n+1):
s *= i
return s
print(fact(n), s) #此處全局變量s被函數(shù)修改
規(guī)則2:局部變量為為組合數(shù)據(jù)類型且未創(chuàng)建,等同于全局變量
ls = ['F', 'f'] #創(chuàng)建了一個(gè)列表類型ls
def func(a):
ls.append(a) #此處ls是列表類型,未真實(shí)創(chuàng)建則等同于全局變量
return
func('C') #全局變量ls被修改
print(ls)
運(yùn)行結(jié)果
>>>
['F', 'f', 'C']
如果創(chuàng)建了一個(gè)ls
ls = ['F', 'f'] #創(chuàng)建了一個(gè)列表類型ls
def func(a):
ls = [] #此處ls是列表類型,真實(shí)創(chuàng)建
ls.append(a)
return
func('C') #局部變量ls被修改
print(ls)
運(yùn)行結(jié)果
>>>
['F', 'f']
使用規(guī)則
- 基本數(shù)據(jù)類型,無(wú)論是否重名,局部變量與全局變量不同
- 可以通過(guò)
global保留字在函數(shù)內(nèi)部聲明全局變量 - 組合數(shù)據(jù)類型,如果局部變量未真實(shí)創(chuàng)建,則是全局變量
lambda函數(shù)
lambda函數(shù)返回函數(shù)名作為結(jié)果
- lambda函數(shù)是一種匿名函數(shù),即沒有名字的函數(shù)
- 使用
lambda保留字定義,函數(shù)名是返回結(jié)果 - lambda函數(shù)用于定義簡(jiǎn)單的、能夠在一行內(nèi)表示的函數(shù)
<函數(shù)名> = lambda<參數(shù)>:<表達(dá)式>
等價(jià)于
def <函數(shù)名>(<參數(shù)>,):
<函數(shù)體>
return <返回值>
例:
>>> f = lambda x,y : x + y
>>> f(10,15)
25
沒有參數(shù)
>>> f = lambda : 'lambda函數(shù)'
>>> print(f())
lambda函數(shù)
謹(jǐn)慎使用lambda函數(shù)
- lambda函數(shù)主要用作一些特定函數(shù)或方法的函數(shù)
- lambda函數(shù)有一些固定使用方式,建議逐步掌握
- 一般情況,建議使用
def定義普通函數(shù)
實(shí)例7:七段數(shù)碼管繪制
問題分析:
通過(guò)七段數(shù)碼管顯示數(shù)字和字母。
turtle繪圖體系→七段數(shù)碼管
效果

實(shí)例講解
基本思路
- 繪制單個(gè)數(shù)字對(duì)應(yīng)的數(shù)碼管
- 獲得一串?dāng)?shù)字,繪制對(duì)應(yīng)的數(shù)碼管
- 獲得當(dāng)前系統(tǒng)時(shí)間,繪制真實(shí)的時(shí)間
步驟1:繪制單個(gè)數(shù)碼管
- 由7個(gè)基本線條組成
- 可以有固定順序
-
不同數(shù)字顯示不同的線條
單個(gè)數(shù)字示意圖
import turtle
def drawLine(draw): #繪制單段數(shù)碼管
turtle.pendown() if draw else turtle.penup() #通過(guò)draw控制是真實(shí)繪制還是只是飛過(guò)去
turtle.fd(40)
turtle.right(90)
def drawDigit(digit): #根據(jù)數(shù)字繪制七段數(shù)碼管
drawLine(True) if digit in [2,3,4,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,1,3,4,5,6,7,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,3,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,6,8] else drawLine(False)
turtle.left(90)
drawLine(True) if digit in [0,4,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,3,5,6,7,8,9] else drawLine(False)
drawLine(True) if digit in [0,1,2,3,4,7,8,9] else drawLine(False)
turtle.left(180)
turtle.penup() #為繪制后續(xù)數(shù)字確定位置
turtle.fd(20) #為繪制后續(xù)數(shù)字確定位置
步驟2:獲取一段數(shù)字,繪制多個(gè)數(shù)碼管
def drawDate(date): #獲得想要輸出的數(shù)字
for i in date:
drawDigit(eval(i))
def main():
turtle.setup(800, 350, 200, 200)
turtle.penup()
turtle.fd(-300)
turtle.pensize(5)
drawDate('20181010')
turtle.hideturtle()
turtle.done()
main()
步驟3:獲得當(dāng)前系統(tǒng)時(shí)間,繪制對(duì)應(yīng)的數(shù)碼管
- 使用time庫(kù)獲得當(dāng)前系統(tǒng)時(shí)間
- 增加年月日標(biāo)記
- 年月日顏色不同
import turtle, time
def drawGap(): #繪制數(shù)碼管間隔
turtle.penup()
turtle.fd(5)
def drawLine(draw): #繪制單段數(shù)碼管
drawGap()
turtle.pendown() if draw else turtle.penup() #通過(guò)draw控制是真實(shí)繪制還是只是飛過(guò)去
turtle.fd(40)
drawGap()
turtle.right(90)
def drawDigit(digit): #根據(jù)數(shù)字繪制七段數(shù)碼管
...(略)
def drawDate(date): #date為日期,格式為'%Y-%m=%d+'
turtle.pencolor('red')
for i in date:
if i == '-':
turtle.write('年', font=('Arial', 18, 'normal'))
turtle.pencolor('green')
turtle.fd(40)
elif i == '=':
turtle.write('月', font=('Arial', 18, 'normal'))
turtle.pencolor('blue')
turtle.fd(40)
elif i == '+':
turtle.write('日', font=('Arial', 18, 'normal'))
else:
drawDigit(eval(i))
def main():
turtle.setup(800, 350, 200, 200)
turtle.penup()
turtle.fd(-300)
turtle.pensize(5)
drawDate(time.strftime('%Y-%m=%d+',time.gtime()))
turtle.hideturtle()
turtle.done()
main()
舉一反三
理解方法思維
- 模塊化思維:確定模塊接口,封裝功能
- 規(guī)則化思維:抽象過(guò)程為規(guī)則,計(jì)算機(jī)自動(dòng)執(zhí)行
- 化繁為簡(jiǎn):將大功能變?yōu)樾」δ芙M合,分而治之
應(yīng)用擴(kuò)展
- 帶小數(shù)點(diǎn)的七段數(shù)碼管
- 帶刷新時(shí)間的倒計(jì)時(shí)效果
- 繪制更多形式的數(shù)碼管
代碼復(fù)用與函數(shù)遞歸
代碼復(fù)用與模塊化設(shè)設(shè)計(jì)
將代碼當(dāng)成資源進(jìn)行抽象
- 代碼資源化:程序代碼是一種用來(lái)表達(dá)計(jì)算的“資源”
- 代碼抽象化:使用函數(shù)等方法對(duì)代碼賦予更高級(jí)別的定義
- 代碼復(fù)用:同一份代碼在需要時(shí)進(jìn)行復(fù)用
函數(shù)和對(duì)象是代碼復(fù)用的兩種主要形式 - 函數(shù):將代碼命名,在代碼層面建立初步抽象
- 對(duì)象:屬性和方法
<a>.<b>()
分而治之
- 通過(guò)函數(shù)或?qū)ο蠓庋b將程序劃分為模塊及模塊間的表達(dá)
- 具體包括:主程序、子程序和子程序間關(guān)系
緊耦合、松耦合
- 緊耦合:兩個(gè)部分之間交流很多,無(wú)法獨(dú)立存在
- 松耦合:兩個(gè)部分之間交流很少,可以獨(dú)立存在
- 模塊內(nèi)部緊耦合、模塊之間松耦合
函數(shù)遞歸的理解
在函數(shù)定義中,調(diào)用函數(shù)自身的方式
兩個(gè)關(guān)鍵特性
- 鏈條:計(jì)算過(guò)程存在遞歸鏈條
- 基例:存在一個(gè)或多個(gè)不需要再次遞歸的實(shí)例
類似數(shù)學(xué)歸納法
函數(shù)遞歸的調(diào)用過(guò)程
以遞歸方式計(jì)算n!:
def fact(n):
if n == 0:
return 1
else:
return n*fact(n-1)
函數(shù)+分支語(yǔ)句
- 遞歸本身是一個(gè)函數(shù),需要函數(shù)定義方式描述
- 函數(shù)內(nèi)部,采用分支語(yǔ)句對(duì)輸入?yún)?shù)進(jìn)行判斷
- 基例和鏈條,分別編寫對(duì)應(yīng)代碼
函數(shù)遞歸實(shí)例解析
字符串反轉(zhuǎn)
將字符串反轉(zhuǎn)后輸出s[::-1]
def rvs(s):
if s == '':
return s
else:
return rvs(s[1:])+s[0]
斐波那契數(shù)列
n=1,2時(shí),F(xiàn)(n)=1;n>2時(shí),F(xiàn)(n)=F(n-1)+F(n-2)
def f(n):
if n == 1 or n == 2:
return 1
else:
return f(n-1)+f(n-2)
漢諾塔問題

需要搬運(yùn)過(guò)程和次數(shù)
count = 0
def hanoi(n, src, dst, mid):
global count
if n == 1:
print("{}:{}->{}".format(1,src,dst))
count += 1
else:
hanoi(n-1, src, mid, dst)
print("{}:{}->{}".format(n,src,dst))
count += 1
hanoi(n-1, mid, dst, src)
PyInstaller庫(kù)的使用
將.py源代碼轉(zhuǎn)換成無(wú)需源代碼的可執(zhí)行文件(Windows下為.exe文件)
PyInstaller是第三方庫(kù),安裝第三方庫(kù)需要pip工具
安裝
cmd命令行
pip install pyinstaller
PyInstaller庫(kù)使用說(shuō)明
cmd命令行
pyinstaller -F <文件名.py>
打包后build和pycache文件夾可刪除,dist文件夾里有exe文件。
常用參數(shù)
| 參數(shù) | 描述 |
|---|---|
-h |
查看幫助 |
--clean |
清理打包過(guò)程中的臨時(shí)文件 |
-D,--onedir
|
默認(rèn)值,生成dist文件夾 |
-F,--onefile
|
在dist文件夾中只生成獨(dú)立的打包文件 |
-i <圖標(biāo)文件名.ico> |
指定打包程序使用圖標(biāo)文件 |
實(shí)例8:科赫雪花小包裹
問題分析
分形幾何
- 一種迭代的幾何圖形,廣泛存在于自然界中
科赫曲線,也叫雪花曲線
一條直線,取中間1/3長(zhǎng)度,作一個(gè)60度角,一階

實(shí)例講解
#KochDrawV1.py
import turtle
def koch(size, n):
if n == 0:
turtle.fd(size)
else:
for angle in [0, 60, -120, 60]:
turtle.left(angle)
koch(size/3, n-1)
def main():
turtle.setup(800, 400)
turtle.penup()
turtle.goto(-300, -50)
turtle.pendown()
turtle.pensize(2)
koch(600, 3)
turtle.hideturtle()
main()
繪制雪花,main()修改為
def main():
turtle.setup(600, 600)
turtle.penup()
turtle.goto(-200, 100)
turtle.pendown()
turtle.pensize(2)
level = 3
koch(400, level)
turtle.right(120)
koch(400, level)
turtle.right(120)
koch(400, level)
turtle.hideturtle()
main()
舉一反三
繪制條件的擴(kuò)展
- 修改分形幾何繪制階數(shù)
- 修改科赫曲線的基本定義及旋轉(zhuǎn)角度
- 修改科赫雪花的基礎(chǔ)框架圖像
分形幾何千千萬(wàn)
