#1函数
##1.1函数的使用
函数是一段具有特定功能的,可重用的语句组。我们使用函数的两个主要目的是:降低编程难度和代码重用,一般函数表达特定功能,是一种功能抽象。语法形式:
def <函数名>(<参数列表>):
<函数体>
return <返回列表值>
需要注意的是,当函数需要返回值时,使用return保留字和返回列表,否则可以没有return语句。
函数的定义:
①函数定义时,所指定的参数是一种占位符。
②函数定义后,如果不经调用,不会被执行。
③函数定义时,参数是输入,函数体是处理,结果是输出(IPO),函数是IPO的一种实现。
注:函数定义时,可以设计可变数量参数,即不确定参数数量。
def <函数名>(<参数>,*b):
<函数体>
return <返回值>
##1.2函数的调用过程
程序调用一个函数需要执行以下4个步骤:
①调用程序在调用处暂停执行。
②在调用时将实参复制给函数的形参。
③执行函数体语句。
④函数调用结束给出返回值,程序回到调用前的暂停处继续执行。
函数的调用:
①调用时要给出实际参数。
②实际参数替换定义中的参数。
③函数调用后得到返回值。
函数的定义和函数的调用需要注意:定义代码不被执行,而调用的时候通过给定实际参数替换定义中的形式参数获得运算结果。
函数可以有参数,也可以没有参数,但必须保留括号:
def <函数名>():
<函数体>
return <返回值>
==可选参数传递:==函数定义时,可以为某些参数指定默认值,构成可选参数。
def <函数名>(<非可选函数>,<可选函数>)
<函数体>
return <返回值>
其中,可选参数必须在非可选参数之后。
函数在调用时,参数可以按照位置或名称方式传递。
##1.3函数的参数传递
首先我们要分清全局变量和局部变量,全局变量贯穿整个程序,而局部变量在函数体内有效。
保留字global:用在函数内部中声明这个变量它是全局变量而不是局部变量。
注:
①局部变量是函数内部的占位符,与全局变量可能重名但不同。
②函数运算结束后,局部变量被释放。
③可以使用global保留字在函数内部使用全局变量。
④局部变量如果是组合数据类型,而且未在函数内部创建,它等同于全局变量。
Is = ["F","f"] #通过使用[]真实创建了一个全局变量列表Is
def func("a"):
Is.append(a) #此处Is是列表类型,未真实创建,则等同于全局变量
return
func("C") #全局变量Is被修改
print(Is)
函数可以返回0个或多个结果:
①return保留字用来传递返回值。
②函数可以没有返回值,也可以没有,可以有return也可以没有。
③return可以传递0个返回值,也可以传递任意多个返回值。
#2 ambda函数
lambda函数是一种匿名函数,即没有名字的函数,是将函数名作为函数结果返回。使用的是lambda保留字。语法形式如下:
def <函数名>(参数列表):
return <表达式>
lambda函数用于定义简单的,能够在一行表示的函数。
注:谨慎使用lambda函数,因为lambda函数主要用作一些特定函数或方法的参数,并且lambda函数有一些固定的使用方式,建议逐步掌握。一般情况下建议使用def定义普通函数。
#3 实例:七段数码管绘制
##3.1普通版
import turtle, datetime
def drawLine(draw): #绘制单段数码管
turtle.pendown() if draw else turtle.penup()
turtle.fd(40)
turtle.right(90)
def drawDigit(d): #根据数字绘制七段数码管
drawLine(True) if d in [2,3,4,5,6,8,9] else drawLine(False)
drawLine(True) if d in [0,1,3,4,5,6,7,8,9] else drawLine(False)
drawLine(True) if d in [0,2,3,5,6,8,9] else drawLine(False)
drawLine(True) if d in [0,2,6,8] else drawLine(False)
turtle.left(90) #向左转向90度
drawLine(True) if d in [0, 4, 5, 6, 8, 9] else drawLine(False)
drawLine(True) if d in [0,2, 3, 5, 6,7, 8, 9] else drawLine(False)
drawLine(True) if d in [0, 1, 2, 3, 4,7, 8, 9] else drawLine(False)
turtle.left(180)
turtle.penup()
turtle.fd(20)
def drawDate(date): #获得需要输出的数字
for i in date:
drawDigit(eval(i)) #通过eval()函数将数字变为正数
def main():
turtle.setup(800, 350, 200, 200)
turtle.penup()
turtle.fd(-300)
turtle.pensize(5)
drawDate(datetime.datetime.now().strftime('%Y%m%d'))
turtle.hideturtle()
turtle.done()
main()
实现效果:
##3.2进阶版
在普通版的基础上,增加了数字之间的间隔,也增添了年月日的效果。
import turtle, 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(d): #根据数字绘制七段数码管
drawLine(True) if d in [2,3,4,5,6,8,9] else drawLine(False)
drawLine(True) if d in [0,1,3,4,5,6,7,8,9] else drawLine(False)
drawLine(True) if d in [0,2,3,5,6,8,9] else drawLine(False)
drawLine(True) if d in [0,2,6,8] else drawLine(False)
turtle.left(90)
drawLine(True) if d in [0, 4, 5, 6, 8, 9] else drawLine(False)
drawLine(True) if d in [0,2, 3, 5, 6,7, 8, 9] else drawLine(False)
drawLine(True) if d in [0, 1, 2, 3, 4,7, 8, 9] else drawLine(False)
turtle.left(180)
turtle.penup()
turtle.fd(20)
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.gmtime()))
turtle.hideturtle()
turtle.done()
main()
实现效果:
#4 代码的复用和模块化设计
程序是由一系列代码组成,函数是程序的一种基本抽象方式,函数封装的直接好处是代码复用。
==函数:==将代码命名,在代码层面建立了初步抽象。
==对象:==属性和方法,在函数之上再次组织进行抽象。
把代码当成资源进行抽象:
①代码资源化:程序代码是一种用来表达计算的"资源"。
②代码抽象化:使用函数等方法对代码赋予更高级的定义。
③代码复用:同一份代码在需要时可以被重复使用。
模块化设计,分而治之:
①通过函数或对象封装将程序划分为模块及模块间的表达。
②具体包括:主程序,子程序和子程序间关系。
③分而治之:一种分而治之,分层抽象,体系化的设计思想。
模块化思维:确定模块接口,封装功能。
规则化思维:抽象过程为规则,计算机自动执行。
化繁为简:将大功能变为小功能组合,分而治之。
模块化设计一般要满足以下两个基本要求:
紧耦合:尽可能合理划分功能块,功能块内部耦合紧密,模块之间交流少,无法独立存在。
松耦合:模块间关系尽可能简单,功能模块之间耦合度低,模块间交流较少,可以独立存在。
#5 函数的递归
函数定义中调用函数自身的方式形成递归。递归是数学归纳法的编程体现。
递归思想:函数+分支
递归链条:线段的组合
递归基例:初始线段
两个关键特征:
①链条:计算过程存在递归链条。
②基例:存在一个或多个不需要再次递归的基例。
递归的实现:函数+分支语句
①递归本身是一个函数,需要函数定义方式描述。
②函数内部,采用分支语句对输入的参数进行判断。
③基例和链条,分别编号对应代码。
微实例
①斐波那契数列
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): #n表示圆盘,src表示初始柱子,dst表示目标柱子,mid表示过渡柱子
global count
if n == 1:
print("{}:{}->{}".format(1, src, dst))
count = count+1
else:
hanoi(n-1, src, mid, dst)
print("{}:{}->{}".format(n, src, dst))
count = count + 1
hanoi(n-1, mid, dst, src)
#6 科赫曲线绘制
import turtle
def koch(size, n): #size表示长度,n表示阶数
if n == 1:
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.speed(0) #控制绘制速度
turtle.penup()
turtle.goto(-300, -50)
turtle.pendown()
turtle.pensize(2)
koch(600, 3) #0阶科赫曲线长度,阶数
turtle.hideturtle()
main()
运行效果:
科赫雪花绘制:
import turtle
def koch(size, n):
if n == 1:
turtle.fd(size)
else:
for angle in [0, 60, -120, 60]:
turtle.left(angle)
koch(size/3, n-1)
def main():
turtle.setup(600, 600)
turtle.speed(0)
turtle.penup()
turtle.goto(-200, 100)
turtle.pendown()
turtle.pensize(2)
level = 5
koch(400, level)
turtle.right(120)
koch(400, level)
turtle.right(120)
koch(400, level)
turtle.hideturtle()
main()
实现效果:
在本篇笔记中,需要特别注意函数的调用,代码的复用,以及函数的递归。还需要详细了解“七段数码管”和“科赫曲线绘制”两个实例,这两个实例都用到了turtle库。