【5】Python函數(shù)和代碼復(fù)用

函數(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ù)碼管顯示時(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)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容