目录
5 函数和代码复用
5.1 函数的定义和使用
5.1.1 函数的理解和定义
作用:降低编程难度 进行代码复用
函数的定义
def 函数名(0个或多个参数)
函数体
return 返回值
例如:计算阶乘n!
def fact(n):
sum=1
for i in range(1,n+1):
sum *= i
return sum
5.1.2 函数的使用及调用过程
调用时要给实际参数去替换定义时的形式(占位)参数
5.1.3 函数的参数传递
函数可以有参数也可以没有参数,但括号必须有
可选参数传递
函数定义时可以为某些参数设定默认值,构成可选参数,要放在后面;放前面的非可选参数是指调用时必须要有的参数
def 函数名(非可选参数,可选参数):
函数体
return 返回值
例如:计算阶乘整除 n!//m
def fact(n,m=1): #如果没给参数m,默认m=1
sum=1
for i in range(1,n+1):
sum *= i
return sum//m
可变参数传递
函数定义时可以设计可变数量的参数,即不确定参数的总量
变量名前带上星号*
def 函数名(参数,*可变参数)
函数体
return 返回值
例如:
def fact(n,*b):
sum=1
for i in range(1,n+1):
sum *= i
for item in b:
sum *= item
return sum
调用fact(10,3),计算过程:10!*3=1088640
调用fact(10,3,5),计算过程:10!*3*5=54432000
参数传递的两种方式
按位置传递 按名称传递
例如:
def fact(n,m=1)
按位置:fact(10,5)
按名称:fact(m=5,n=10)
5.1.4 函数的返回值
返回0或多个结果
不管要不要传递返回值,都可以加上return
例如:
def fact(n,m=1):
sum=1
for i in range(1,n+1):
sum *= i
return sum//m,n,m
调用fact(10,5) 结果为:(725760, 10, 5) ------元组类型
或者a,b,c=fact(10,5) 用abc接收结果
5.1.5 局部变量和全局变量
局部变量:函数内部使用
全局变量:函数外部试用
例如:
n,m=10,100
def fact(n):
m=1
for i in range(1,n+1):
m=m*i
return m
print(fact(n),m)
结果:
3628800 100
使用规则:
规则1:基本数据类型,无论是否重名,局部变量和全局变量是不同变量
局部变量是函数内部的占位符,与全局变量可能重名但不同
函数运算结束后,局部变量被释放(这个局部变量不再存在)
可以使用global保留字在函数内部使用全局变量
例如:
n,m=10,100
def fact(n):
global m #声明这个m是函数外部的全局变量m
for i in range(1,n+1):
m=m*i
return m
print(fact(n),m)
结果:
362880000 362880000
规则2:局部变量为组合数据类型且未在函数内部真实创建,等同于全局变量
例如:
p=["x","y","z"] #使用[]真实创建了全局变量列表p
def func(a):
p.append(a) #此处p是列表类型,未真实创建,等同于全局变量
return
func("o")
print(p)
结果:
['x', 'y', 'z', 'o']
对比:
p=["x","y","z"]
def func(a):
p=[] #创建了p,就是局部变量
p.append(a)
return
func("o")
print(p)
结果:
['x', 'y', 'z']
5.1.6 lambda函数
主要用作一些特定函数或方法的参数,有些函数的参数就是一个函数,这种情况用lambda函数。一般情况下还是用def
用法:函数名=lambda 参数:表达式
等价于:
def 函数名(参数):
函数体
return 返回值
例如:
>>>f = lambda x,y : x+y
>>>f(5,6)
11
>>>g=lambda:"函数哦" #没有参数
>>>print(g())
函数哦
5.2 实例七:七段数码管绘制
5.2.1 问题分析
七段数码管也就是数字8的电子显示
利用turtle绘图体系绘制电子时间显示屏
思路:
绘制一个数码管
获得一串数字,绘制对应数码管
获得当前系统时间,绘制对应数码管
5.2.2 实例编写
import turtle as t
import time
#绘制数码管间隔
def gap():
t.penup()
t.fd(5)
#绘制一段线
def line(a):
gap()
if a:
t.pendown()
else:
t.penup()
t.fd(50)
gap()
t.right(90)
#绘制数字数码管
def digit(b):
#判断各段有哪些数字要显示
#第1条
if b in [2,3,4,5,6,7,8,9]:
line(True)
else:
line(False)
#简写:line(True) if d in [2,3,4,5,6,7,8,9] else line(False)
#第2条
if b in [0,1,3,4,5,6,7,8,9]:
line(True)
else:
line(False)
#第3条
if b in [0,2,3,5,6,8,9]:
line(True)
else:
line(False)
#第4条
if b in [0,2,6,8]:
line(True)
else:
line(False)
#回到起点,此时不需要右转,所以左转回来
t.left(90)
#第5条
if b in [0,4,5,6,8,9]:
line(True)
else:
line(False)
#第6条
if b in [0,2,3,5,6,7,8,9]:
line(True)
else:
line(False)
#第7条
if b in [0,1,2,3,4,7,8,9]:
line(True)
else:
line(False)
t.left(180)
t.penup()
t.fd(20)
#获取数字
def date(d):
t.pencolor("red")
for i in d:
if i == "年":
t.write("年",font=("Arial",36,"normal"))
t.pencolor("green")
t.fd(60)
elif i == "月":
t.write("月",font=("Arial",36,"normal"))
t.pencolor("blue")
t.fd(60)
elif i == "日":
t.write("日",font=("Arial",36,"normal"))
else:
digit(eval(i))
def main():
t.bgcolor("black")
t.hideturtle()
t.tracer(False)
#t.speed(10)
t.setup(1200,350,200,200)
t.penup()
t.fd(-300)
t.pensize(5)
date(time.strftime("%Y年%m月%d日",time.gmtime()))
t.done()
main()
5.3 代码复用与函数递归
5.3.1 代码复用与模块化设计
用函数和对象两种主要形式进行代码复用
函数:将代码命名,在代码层面建立了初步抽象,将代码变成功能组
对象:通过属性和方法,将一组变量或一组函数进一步抽象
模块化设计:通过函数或对象封装程序,将程序划分为模块及模块间的表达;关注主程序、子程序和子程序间的关系
紧耦合:两部分交流多,无法独立存在
松耦合:两部分交流少,可以独立存在
函数的参数和返回值就是函数与其他代码之间的交流通道,通道越少约清晰,函数复用的可能性越高,所以模块内部(函数内)尽量是紧耦合,模块外部(函数外部)之间松耦合,方便调用
5.3.2 函数递归
经典例子:阶乘
递归定义
调用函数自身,两个特性:
链条:计算过程间的对应关系
基例:存在一个或多个不需要递归(递归的最末端)
所以递归最重要的是找到链条和基例
递归的实现
函数+分支语句
递归本身是一个函数 函数内部用分支语句对基例和链条分别编写对应代码
def fact(n):
if n==0:
return 1
else:
return n*fact(n-1)
例:字符串反转
def res(s):
if s=="":
return s
else:
return res(s[1:])+s[0] #妙!把第一个字符放到最后面
例:斐波那契数列
def f(n):
if n==1 or n==2:
return 1
else:
return f(n-1)+f(n-2)
例:汉诺塔问题的解法
问题描述:n个大小不一的圈套在柱子上,通过一个辅助柱子移到另一个柱子,要求移动后也是上小下大
基例:只有一个圈,直接移
链条:先把上面的n-1个圆盘从起始搬到辅助柱子,剩下一个最大的直接搬到目标柱子,再把辅助柱子的圆盘搬到目标柱子
count=0 #记录移动次数
def hanoi(n,left,mid,right): #分别为圈数、起始柱子、辅助柱子、目标柱子
global count #用global全局变量,否则每次调用都被清0
if n==1:
print("{}: {}->{}".format(1,left,right))
count=count+1
else:
#先把上面的n-1个圆盘从起始搬到辅助柱子,剩下一个最大的直接搬到目标柱子
hanoi(n-1,left,mid,right)
print("{}: {}->{}".format(n,left,right))
count=count+1
#再把辅助柱子的圆盘搬到目标柱子,至于怎么搬,递归就可以实现
hanoi(n-1,mid,left,right)
#调用
hanoi(4,"A","B","C")
print("COUNT=",count)
结果:
1: A->C
2: A->C
1: B->C
3: A->C
1: B->C
2: B->C
1: A->C
4: A->C
1: B->C
2: B->C
1: A->C
3: B->C
1: A->C
2: A->C
1: B->C
COUNT= 15
5.4 模块4:pyinstaller库的使用
5.4.1 pyinstaller库的介绍
pyinstaller库是第三方库,需要额外安装,官方网站:PyInstaller Manual — PyInstaller 5.3 documentation
将 .py 源代码转换成无需源代码的可执行文件---打包为 .exe
打包过程使用pyinstaller,打包完成后就不需要了
通过pyinstaller将Python源代码转换为Windows、Mac OS、Linus可执行的文件
安装第三方库---pip工具
win+R 打开cmd命令
pip install +库名 安装第三方库
pip list 查看已安装库
pip uninstall 卸载已安装库
pip show 显示已安装库信息
方法1:右击IDLE打开所在文件夹---打开scripts文件夹---shift+右击---选择打开powershell窗口---输入pip install+库名
方法2:win+R 打开cmd命令---输入:pip install pyinstaller
方法3:自定义安装,去官网找安装包或路径安装,下载后自动安装
方法4:下载文件安装,在 www.lfd.uci.edu/~gohlke/pythonlibs可以找到所有第三方库的文件
5.4.2 pyinstaller库的使用
方法1:win+R 打开cmd命令
方法2:在.py 的文件夹空白处 shift+右击---选择打开powershell窗口
-F 打包:pyinstaller -F 文件名.py
留下dist里的.exe就可以,build和spec(可能还有_pycache_)可以删掉
-h 查看帮助:
--clean 清理临时文件:pyinstaller -F --clean 文件名.py
-i 修改图标:pyinstaller -i 图标文件名.ico -F 文件名.py
iconfont-阿里巴巴矢量图标库 下载ico图片
制作ico图标 | 在线ico图标转换工具 方便制作favicon.ico - 比特虫 - Bitbug.net 转换为.ico
修改后在dist里面图标可能没变,但是移动到其他位置后就变了
5.5 实例八:科赫雪花
5.5.1 问题分析
分形几何
一种迭代关系的几何图形,广泛存在于自然界,简单说就是整体和局部的结构相似
科赫雪花曲线
5.5.2实例编写
用Python绘制科赫雪花曲线
一条线段三等分,然后中间凸起两条(等边三角形),以此类推,不断迭代
基例:0阶(线段)
链条:每个线段凸起
import turtle as t
def koch(size,n): #size表示长度,n表示绘制阶数
if n==0:
t.fd(size)
else:
for angle in [0,60,-120,60]:
t.left(angle)
koch(size/3,n-1)
def main():
t.setup(800,400)
t.speed(10)
t.pu()
t.goto(-300,-50)
t.pd()
t.pensize(2)
koch(600,3)
t.hideturtle()
main()
绘制结果:
如何形成雪花?以三角形为基础,两次转弯
import turtle as t
def koch(size,n): #size表示长度,n表示绘制阶数
if n==0:
t.fd(size)
else:
for angle in [0,60,-120,60]:
t.left(angle)
koch(size/3,n-1)
def main():
t.setup(1200,800)
#t.tracer(False)
t.speed(10)
t.pu()
t.goto(-300,200)
t.pd()
t.pensize(2)
level=3
koch(600,level)
t.right(120) #转两次弯变成三角形
koch(600,level)
t.right(120)
koch(600,level)
t.hideturtle()
main()
如果尝试改变阶数和基础图形? 改参数,注意找好角度关系
import turtle as t
def koch(size,n): #size表示长度,n表示绘制阶数
if n==0:
t.fd(size)
else:
for angle in [0,60,-120,60]:
t.left(angle)
koch(size/3,n-1)
level=eval(input("请输入雪花阶数:"))
r=eval(input("基础形状为正?边形:"))
angle=(r-2)*180/r
t.setup(1200,800)
#t.tracer(False)
t.speed(0)
t.pu()
t.goto(-300,200)
t.pd()
t.pensize(2)
koch(400,level)
for i in range(r-1):
t.right(180-angle)
koch(400,level)
例如: