Python基础学习笔记(四)函数和代码复用
函数的定义和使用
1、函数理解与定义
函数是一段具有特定功能的、可重用的语句组,是一种功能的抽象,基本作用是降低编程难度和代码复用。
def <函数名>(<参数>):
<函数体>
return <返回值>
2、函数使用和调用
调用时要给出实际参数,实际参数会替换掉定义中的参数,函数调用后得到返回值。
函数参数传递:
可以有参数也可以没有,但是必须保留括号。可以指定默认值,构成可选参数。非可选参数意味着调用该函数时必须有这个参数,放在所有可选参数前面。可选参数意味着可以不给出这个参数,如果给出按给出参数执行函数,如果不给按默认参数执行函数。
def <函数名>(<非可选参数>, <可选参数>):
<函数体>
return <返回值>
def fact(n, m = 1):
s = 1
for i in range(1, n+1):
s *= i
return s//m
>>> fact(10)
3628800
>>> fact(10, 5)
725760
可变参数定义:设计函数接收的参数是可变数量的。先确定要给的参数放在最前面,用*b表达不确定的参数。
def <函数名>(<参数>, *b):
<函数体>
return <返回值>
def fact(n, *b):
s = 1
for i in range(1, n+1):
s *= i
for item in b:
s *= item
return s
调用函数时,可以按照位置(默认方式)或者名称方式传递:
def fact(n, m = 1):
s = 1
for i in range(1, n+1):
s *= i
return s//m
>>> fact(10, 5)
>>> fact(m=5, n=10)
函数返回值
可以返回0或者多个结果,使用return传递返回值。可以有返回值也可以没有。
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)
3、局部变量和全局变量
局部变量:是函数内部使用的变量,仅在函数内部使用
全局变量:整个程序中都在使用的变量
使用规则:
局部变量和全局变量是不同的变量:对于基本的数据类型,无论重名与否,两者就是不同的变量。函数运算结束后其内部的局部变量被释放,可以使用global在函数内部使用全局变量。
n, s = 10, 100
def fact(n):
s = 1
for i in range(1, n+1):
s *= i
return s
print(fact(n), s)
>>>
3628800 100
n, s = 10, 100
def fact(n):
global s
for i in range(1, n+1):
s *= i
return s
print(fact(n), s)
>>>
3628800 3628800
局部变量如果是组合数据类型而且未在函数内部创建,它等同于全局变量。
ls = ["F", "f"] #创建列表
def func(a):
ls.append(a)
returen
func("C")
print(ls)
>>>
["F", "f", "C"]
ls = ["F", "f"] #创建列表
def func(a):
ls = []
ls.append(a)
returen
func("C")
print(ls)
>>>
["F", "f"]
4、lambda函数
lambda函数返回函数名作为结果,是一种匿名函数,仅用于定义简单的、能够在一行内表示的函数。谨慎使用,主要用作一些特定函数或者方法的参数,还有一些固定的使用方式。
<函数名> = lambda<参数>: <表达式>
>>> f = lambda x, y : x + y
>>> f(10, 15)
25
>>> f = lambda : "调用成功"
>>> print(f())
调用成功
示例
#七段数码管绘制
'''问题拆解:
首先应该学会绘制一条线,
接着就可以绘制七条线,
然后如何组合得到数字显示,
最后如何获取时间并且将它显示出来。'''
import turtle
import time
def drawGap():#希望数码管之间有一定的间隔
turtle.penup()
turtle.fd(5)
def drawLine(draw): #绘制单段数码管
drawGap()
turtle.pendown() if draw else turtle.penup()
turtle.fd(40)
drawGap()
turtle.right(90)
def drawDigit(digit):#根据数字绘制七段数目管
#核心思想是拆分每一个笔被那些数字需要,需要时落下画线,不需要时抬起画笔
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()
turtle.fd(20)#为后续数字确定位置
def drawDate(data):
#做出约定标记年月日 例如 %Y-%m*%d&
turtle.pencolor("red")#规定年份颜色
for i in data:
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():
turtel.setup(800, 350, 200, 200)
turtel.penup()
turtle.fd(-300)
turtle.pensize(5)
drawDate(time.strftime('%Y-%m*%d&', time.gmtime())) #获得时间并格式化
turtle.hideturtle()
turtle.done()
main()
代码复用和函数递归
把代码当成资源进行抽象:
代码资源化:程序代码是一种用来表达计算的“资源”
代码抽象化:使用函数等方法对代码赋予更高级别的定义
代码复用:同一段代码在需要的时候可以被重复使用,一般使用函数或者对象实现代码复用,函数在代码层面建立了初步抽象,而对象则是在函数之上再次进行组织进行抽象。
模块化设计的核心思想是分而治之,也就是通过函数或者对象封装将程序分为模块以及模块间的表达,包括主程序、子程序和子程序之间的关系。
紧耦合:两个部分之间的交流很多,无法独立存在
松耦合:两个部分之间的交流很少,可以独立存在
函数之间的参数和返回值就是程序与程序之间的交流通道。这样的交流通道越清晰,代码就越容易被复用。所以我们希望模块内部紧耦合,模块之间松耦合。
函数递归:在函数设计中调用函数自身的方式。递归有两个关键的特征:
链条:计算过程中存在递归链条
基例:存在一个或者多个不需要再次递归的基例(基础的实例)
实现递归需要结合函数和分支语句,递归本身是一个函数,需要函数定义方式描述;在函数内部,需要利用分支语句判断输入参数是否属于基例。
#计算n的阶乘
def fact(n):
if n == 0
return 1
else:
return n*fact(n-1)
#字符串反转:将字符串s反转后输出
>>> s[::-1]
def rvs(s):
if s == "":
return s
else:
return rvs(s[1:]+s[0])
#费布拉切数列
def F(n):
if n == 1 or n == 2:
return 1
else:
return F(n-1) + F(n-2)
#汉诺塔问题
count = 0
def hanoi(n, src, dst, mid):
global count
if n == 1 #如果只有一个圆盘
print("{}:{}->{}".format(1, src, dst))#直接将1号圆盘从起始搬运到目标
count += 1
else:
#假设我们将n-1个圆盘搬运到中间圆盘,就能将最后一个圆盘搬运到目标圆盘
hanoi(n-1, src, mid, dst)
print("{}:{}->{}".format(n, src, dst))
count += 1
hanoi(n-1, mid, dst, src)
示例
#科赫雪花
'''
用于分形的曲线,本身就是迭代过程。
'''
#KochDrawV1.py
import turtle
def koch(size, n):
if n == 0:
turtle.fd(size)#n=0则绘制直线
else:
for angle in [0, 60, -120, 60]:
turtle.left(angle)
koch(size/3, n-1)
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()
打包小程序形成可执行文件:打开cmd
pyinstaller -i curve.ico -F KochDrawV1.py
附-PyInstaller库
将.py源代码转换成无需源代码的可执行文件。他是一个第三方库,需要额外安装(http://www.pyinstaller.org)
安装:打开cmd,执行 pip install pyinstaller
使用:
在源代码所在目录,通过cmd(windows的命令行)执行pyinstaller -F <文件名.py>。完成后会生成三个文件夹,dist中有同名exe文件。
常用参数:
参数 | 描述 |
---|---|
-h | 查看帮助 |
–clean | 清理打包过程中的临时文件 |
-D, --onedir | 默认值,生成dist文件夹 |
-F, --onefile | 在dist文件夹中只生成独立的打包文件 |
-i<图标文件名.ico> | 指定打包程序使用的图标(icon)文件 |