【笔记】《python语言程序设计》—函数和代码复用
一、前言
学习就是一个不断的自下而上,自上而下的过程。
前段时间,学着用python实现网站的数据爬取,隐约get到python的一些语法和用法,感觉就是语法不难,关键在于解决问题的思维。
这是需求驱动后的学习。接下来,就需要对python进行系统地了解。
很早之前搜知乎的时候,就搜到MOOC上的一门《python语言程序设计》课程,讲得很好,而且,我还下载了课件,溜了一遍,感觉就挺有趣的。
趁着有了实战经验,就把这门入门课刷了一遍。果然是门好课!很适合小白入门,并系统学习,整个教学过程循序渐进,深入浅出,提纲挈领,很有意思!
课程是北京理工大学嵩天老师的《python语言程序设计》课程,现在已经开了11次课了。课程每个小视频短则几分钟,最长也不超过20分钟,不容易劝退。每章讲解有复习回顾及小结,在平台python123上有每章的练习和测试,直接反馈结果,激发继续学下去的兴趣。
个人感觉,老师说话速度慢了些,调成了2倍速播放,然后,花了大约3天的时间,把所有的视频,课件,练习和测试都刷了一遍,感觉对python的了解更系统了!
趁热打铁,把每章的知识点和练习、测试再进行整理回顾一下。
以下内容均来自课程:《python语言程序设计》 及平台python123,感兴趣的看课程视频,亲自练习,效果更好~
二、知识点
1.函数的定义与使用
-
函数的理解与定义
①一段具有特定功能的,可重用的语句组
②一种功能的抽象,一般函数表达特定功能
③两个作用:降低编程难度和代码复用
def <函数名>(<参数(0个或多个>): <函数体> return <返回值>
④函数定义时,所指定的参数是一种占位符;如果不经过调用,不会被执行;参数是输入,函数体是处理,结果是输出(IPO)
-
函数的使用及调用过程
①调用是运行函数代码的方式
②调用时要给出实际参数;实际参数替换定义中的参数;函数调用后得到返回值;
-
函数的参数传递
①函数可以有参数,也可以没有,但必须保留括号;
②函数定义时可以为某些参数指定默认值,构成可选参数;
③函数定义时可以设计可变数量参数,即不确定参数总数量
def <函数名>(<参数>,*b): <函数体> return <返回值>
④函数调用时,参数可以按照位置或名称方式传递;
#默认参数m为1
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
,也可以没有③多个返回结果以元组类型呈现
-
局部变量和全局变量
①局部变量和全局变量是不同变量:局部变量是函数内部的占位符,与全局变量可能重名但不同;函数运算结束后,局部变量被释放;可以使用
global
保留字在函数内部使用全局变量;
②局部变量为组合数据类型且未创建,等同于全局变量
规则2.png-
lambda函数
①lambda函数返回函数名作为结果
②lambda函数是一种匿名函数,即没有名字的函数
③使用
lambda
保留字定义,函数名是返回结果④lambda函数用于定义简单的、能够在一行内表示的函数
⑤谨慎使用lambda函数:该函数主要用作一些特定函数或方法的参数;该函数有一些固定使用方式,建议逐步掌握;一般情况,建议使用
def
定义的普通函数<函数名>=lambda<参数>:<表达式>
2.实例7:七段数码管绘制
绘制效果:
time_paint.gifimport 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(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(date):
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()
3.代码复用与函数递归
-
代码复用与模块化设计
①代码复用:把代码当成资源进行抽象:代码资源化(程序代码是一种用来表达计算的“资源”);代码抽象化(使用函数等方法对代码赋予更高级别的定义);代码复用(同一份代码在需要时可以被重复使用)
②函数和对象(属性和方法)是代码复用的两种主要形式;
③模块化设计:通过函数或对象封装将程序划分为模块及模块间的表达;分而治之;
④紧耦合和松耦合:前者表示两个部分之间交流很多,无法独立存在;后者表示两个部分之间交流较少,可以独立存在;模块内部紧耦合,模块之间松耦合;
-
函数递归的理解
①递归:函数定义中调用函数自身的方式;
②两个关键特征:(1)链条:计算过程存在递归链条;(2)基例:存在一个或多个不需要再次递归的基例;
-
函数递归的调用过程
①递归本身是一个函数,需要函数定义方式描述;
②函数内部,采用分支语句对输入参数进行判断;
③基例和链条,分别编写对应代码;
-
函数递归实例解析
①字符串反转
#将字符串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)
4.模块4:Pyinstaller库的使用
-
Pyinstaller库基本介绍
①将.py源代码转换成无需源代码的可执行文件;
②第三方库,使用
pip install pyinstaller
安装; -
Pyinstaller库使用说明
①简单使用:(cmd命令行)
pyinstaller -F <文件名.py>
②常用参数:
参数 描述 -h
查看帮助 --clean
清理打包过程中的临时文件 -D
,--onedir
默认值,生成dist文件夹 -F
,--onefile
在dist文件夹中只生成独立的打包文件 -i <图标文件名.ico>
指定打包程序使用的图标(icon)文件 举例:
pyinstaller -i curve.ico -F SevenDigitsDrawV2.py
5.实例8:科赫雪花小包裹
科赫雪花小包裹.png描述:科赫曲线,也叫雪花曲线。绘制科赫曲线。获得用户输入的整数N,作为阶,绘制N阶科赫曲线。
下图为3阶科赫曲线。
import turtle
def koch(size, n):
if n==0:
turtle.fd(size)
else:
for angel in [0,60,-120,60]:
turtle.left(angel)
koch(size/3,n-1)
def main(level):
turtle.setup(800,800)
turtle.penup()
turtle.goto(-200, 100)
turtle.pendown()
turtle.pensize(2)
turtle.hideturtle()
koch(300,level)
turtle.right(120)
koch(300,level)
turtle.right(120)
koch(300,level)
turtle.done()
try:
level = eval(input("请输入科赫曲线的阶: "))
main(level)
except:
print("输入错误")
三、练习
1. 实例7:七段数码管绘制
同上
2. 实例8:科赫雪花小包裹
同上
3. 任意累积
描述:请根据编程模板补充代码,计算任意个输入数字的乘积。
注意,仅需要在标注...的地方补充一行或多行代码。
def cmul(*b):
m=1
for i in b:
m*=i
return m
print(eval("cmul({})".format(input())))
4. 斐波那契数列计算
描述:根据编程模板补充代码,计算斐波那契数列的值,具体功能如下:
获取用户输入整数N,其中,N为正整数
计算斐波那契数列的值
如果将斐波那契数列表示为fbi(N),对于整数N,值如下:
fbi(1)和fbi(2)的值是1,当N>2时,fbi(N) = fbi(N-1) + fbi(N-2)
请采用递归方式编写。
def fbi(n):
if (n==1) or (n==2):
f=1
else:
f=fbi(n-1)+fbi(n-2)
return f
n = eval(input())
print(fbi(n))
5.汉诺塔实践
描述:汉诺塔问题大家都清楚,这里不再赘述。
请补充编程模板中代码,完成如下功能:
有三个圆柱A、B、C,初始时A上有N个圆盘,N由用户输入给出,最终移动到圆柱C上。
每次移动步骤的表达方式示例如下:[STEP 10] A->C。其中,STEP是步骤序号,宽度为4个字符,右对齐。
请编写代码,获得输入N后,输出汉诺塔移动的步骤。
输入格式
一个整数
输出格式
每个步骤一行,每行参考格式如下:[STEP 10] A->C
steps = 0
def hanoi(src, des, mid, n):
global steps
if n == 1:
steps+=1
print("[STEP{:>4}] {}->{}".format(steps, src, des))
else:
hanoi(src,mid,des,n-1)
steps+=1
print("[STEP{:>4}] {}->{}".format(steps, src, des))
hanoi(mid,des,src,n-1)
N = eval(input())
hanoi("A", "C", "B", N)
四、测试
1.选择题
-
以下选项不是函数作用的是:
A 复用代码
B 提高代码执行速度
C 降低编程复杂度
D 增强代码可读性
函数不能直接提高代码执行速度。
- 下列程序的输出结果为:
def f(a,b):
a=4
return a+b
def main():
a=5
b=6
print(f(a,b),a+b)
main()
A 10 11
B 11 10
C 11 11
D 10 10
这里没有全局变量,都是函数局部变量的运算。
- 以下关于Python函数说法错误的是:
def func(a,b):
c=a**2+b
b=a
return c
a=10
b=100
c=func(a,b)+a
A 该函数名称为func
B 执行该函数后,变量a的值为10
C 执行该函数后,变量c的值为200
D 执行该函数后,变量b的值为100
这里没有全局变量,请在IDLE中执行代码观察结果。
-
以下关于函数调用描述正确的是:
A 函数和调用只能发生在同一个文件中
B 自定义函数调用前必须定义
C Python内置函数调用前需要引用相应的库
D 函数在调用前不需要定义,拿来即用就好
函数调用前必须已经存在函数定义,否则无法执行。
Python内置函数直接使用,不需要引用任何模块。
-
以下关于模块化设计描述错误的是:
A 应尽可能合理划分功能块,功能块内部耦合度低
B 应尽可能合理划分功能块,功能块内部耦合度高
C 高耦合度的特点是复用较为困难
D 模块间关系尽可能简单,模块之间耦合度低
模块内高耦合、模块间低耦合。
-
以下对递归描述错误的是:
A 递归程序都可以有非递归编写方法
B 书写简单
C 一定要有基例
D 执行效率高
递归不提高程序执行效率。
任何递归程序都可以通过堆栈或队列变成非递归程序(这是程序的高级应用)。
-
以下关于函数说法错误的是:
A 函数可以看做是一段具有名字的子程序
B 对函数的使用必须了解其内部实现原理
C 函数通过函数名来调用
D 函数是一段具有特定功能的、可重用的语句组
调用函数不需要知道函数内部实现原理,只需要知道调用方法(即接口)即可。
-
哪个选项对于函数的定义是错误的?
A def vfunc(*a,b):
B def vfunc(a,b):
C def vfunc(a,*b):
D def vfunc(a,b=2):
def vfunc(a, b) 是错误的定义:a表示可变参数,可变参数只能放在函数参数的最后。
-
关于return语句,以下选项描述正确的是:
A 函数中最多只有一个return语句
B return只能返回一个值
C 函数可以没有return语句
D 函数必须有一个return语句
函数可以包含0个或多个return语句
-
以下关于递归函数基例的说法错误的是:
A 递归函数必须有基例
B 递归函数的基例决定递归的深度
C 递归函数的基例不再进行递归
D 每个递归函数都只能有一个基例
每个递归函数至少存在一个基例,但可能存在多个基例。
2.程序设计题
- 随机密码生成
描述:补充编程模板中代码,完成如下功能:
以整数17为随机数种子,获取用户输入整数N为长度,产生3个长度为N位的密码,密码的每位是一个数字。每个密码单独一行输出。
产生密码采用random.randint()函数
import random
def genpwd(length):
a=10**(length-1)
b=10**length-1
return '{}'.format(random.randint(a,b))
length = eval(input())
random.seed(17)
for i in range(3):
print(genpwd(length))
- 连续质数计算
描述:补充编程模板中代码,完成如下功能:
获得用户输入数字N,计算并输出从N开始的5个质数,单行输出,质数间用逗号,分割。
注意:需要考虑用户输入的数字N可能是浮点数,应对输入取整数;最后一个输出后不用逗号。
def prime(m):
for i in range(2,m):
if m % i == 0:
return False
return True
n = eval(input())
n_ = int(n)
n_ = n_+1 if n_ < n else n_
count = 5
while count > 0:
if prime(n_):
if count > 1:
print(n_, end=",")
else:
print(n_, end="")
count -= 1
n_ += 1
这个代码注意:
(1) 需要对输入小数情况进行判断,获取超过该输入的最小整数(这里没用floor()函数);
(2) 对输出格式进行判断,最后一个输出后不增加逗号(这里没用.join()方法)。
【笔记】《python语言程序设计》—Python基本语法元素