【笔记】《python语言程序设计》—函数和代码复用

一、前言

学习就是一个不断的自下而上,自上而下的过程。

前段时间,学着用python实现网站的数据爬取,隐约get到python的一些语法和用法,感觉就是语法不难,关键在于解决问题的思维。

这是需求驱动后的学习。接下来,就需要对python进行系统地了解。

很早之前搜知乎的时候,就搜到MOOC上的一门《python语言程序设计》课程,讲得很好,而且,我还下载了课件,溜了一遍,感觉就挺有趣的。

趁着有了实战经验,就把这门入门课刷了一遍。果然是门好课!很适合小白入门,并系统学习,整个教学过程循序渐进,深入浅出,提纲挈领,很有意思!

课程是北京理工大学嵩天老师的《python语言程序设计》课程,现在已经开了11次课了。课程每个小视频短则几分钟,最长也不超过20分钟,不容易劝退。每章讲解有复习回顾及小结,在平台python123上有每章的练习和测试,直接反馈结果,激发继续学下去的兴趣。

个人感觉,老师说话速度慢了些,调成了2倍速播放,然后,花了大约3天的时间,把所有的视频,课件,练习和测试都刷了一遍,感觉对python的了解更系统了!

趁热打铁,把每章的知识点和练习、测试再进行整理回顾一下。

以下内容均来自课程:《python语言程序设计》 及平台python123,感兴趣的看课程视频,亲自练习,效果更好~

二、知识点

1.函数的定义与使用

  1. 函数的理解与定义

    ①一段具有特定功能的,可重用的语句组

    ②一种功能的抽象,一般函数表达特定功能

    ③两个作用:降低编程难度和代码复用

    def <函数名>(<参数(0个或多个>):
        <函数体>
        return <返回值>
    

    ④函数定义时,所指定的参数是一种占位符;如果不经过调用,不会被执行;参数是输入,函数体是处理,结果是输出(IPO)

  2. 函数的使用及调用过程

    ①调用是运行函数代码的方式

    ②调用时要给出实际参数;实际参数替换定义中的参数;函数调用后得到返回值;

【笔记】《python语言程序设计》—函数和代码复用_第1张图片
函数调用过程.png
  1. 函数的参数传递

    ①函数可以有参数,也可以没有,但必须保留括号;

    ②函数定义时可以为某些参数指定默认值,构成可选参数;

    ③函数定义时可以设计可变数量参数,即不确定参数总数量

    def <函数名>(<参数>,*b):
        <函数体>
        return <返回值>
    
【笔记】《python语言程序设计》—函数和代码复用_第2张图片
可变参数传递.png

④函数调用时,参数可以按照位置或名称方式传递;

#默认参数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)
  1. 函数的返回值

    ①函数可以返回0个或多个结果

    ②可以有return,也可以没有

    ③多个返回结果以元组类型呈现

【笔记】《python语言程序设计》—函数和代码复用_第3张图片
多个返回值.png
  1. 局部变量和全局变量

    ①局部变量和全局变量是不同变量:局部变量是函数内部的占位符,与全局变量可能重名但不同;函数运算结束后,局部变量被释放;可以使用global保留字在函数内部使用全局变量;

【笔记】《python语言程序设计》—函数和代码复用_第4张图片
规则1.png

②局部变量为组合数据类型且未创建,等同于全局变量

【笔记】《python语言程序设计》—函数和代码复用_第5张图片
规则2.png
  1. lambda函数

    ①lambda函数返回函数名作为结果

    ②lambda函数是一种匿名函数,即没有名字的函数

    ③使用lambda保留字定义,函数名是返回结果

    ④lambda函数用于定义简单的、能够在一行内表示的函数

    ⑤谨慎使用lambda函数:该函数主要用作一些特定函数或方法的参数;该函数有一些固定使用方式,建议逐步掌握;一般情况,建议使用def定义的普通函数

    <函数名>=lambda<参数>:<表达式>
    

2.实例7:七段数码管绘制

绘制效果:

time_paint.gif
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(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. 函数递归的理解

    ①递归:函数定义中调用函数自身的方式;

    ②两个关键特征:(1)链条:计算过程存在递归链条;(2)基例:存在一个或多个不需要再次递归的基例;

  3. 函数递归的调用过程

    ①递归本身是一个函数,需要函数定义方式描述;

    ②函数内部,采用分支语句对输入参数进行判断;

    ③基例和链条,分别编写对应代码;

  4. 函数递归实例解析

    ①字符串反转

    #将字符串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库的使用

  1. Pyinstaller库基本介绍

    ①将.py源代码转换成无需源代码的可执行文件;

    ②第三方库,使用pip install pyinstaller安装;

  2. 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:科赫雪花小包裹

描述:科赫曲线,也叫雪花曲线。绘制科赫曲线。获得用户输入的整数N,作为阶,绘制N阶科赫曲线。

下图为3阶科赫曲线。

【笔记】《python语言程序设计》—函数和代码复用_第6张图片
科赫雪花小包裹.png
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. 斐波那契数列计算

描述:根据编程模板补充代码,计算斐波那契数列的值,具体功能如下:

  1. 获取用户输入整数N,其中,N为正整数

  2. 计算斐波那契数列的值

如果将斐波那契数列表示为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.选择题

  1. 以下选项不是函数作用的是:

    A 复用代码

    B 提高代码执行速度

    C 降低编程复杂度
    D 增强代码可读性

函数不能直接提高代码执行速度。

  1. 下列程序的输出结果为:
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

这里没有全局变量,都是函数局部变量的运算。

  1. 以下关于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中执行代码观察结果。

  1. 以下关于函数调用描述正确的是:

    A 函数和调用只能发生在同一个文件中

    B 自定义函数调用前必须定义

    C Python内置函数调用前需要引用相应的库

    D 函数在调用前不需要定义,拿来即用就好

函数调用前必须已经存在函数定义,否则无法执行。

Python内置函数直接使用,不需要引用任何模块。

  1. 以下关于模块化设计描述错误的是:

    A 应尽可能合理划分功能块,功能块内部耦合度低

    B 应尽可能合理划分功能块,功能块内部耦合度高

    C 高耦合度的特点是复用较为困难

    D 模块间关系尽可能简单,模块之间耦合度低

模块内高耦合、模块间低耦合。

  1. 以下对递归描述错误的是:

    A 递归程序都可以有非递归编写方法

    B 书写简单

    C 一定要有基例

    D 执行效率高

递归不提高程序执行效率。

任何递归程序都可以通过堆栈或队列变成非递归程序(这是程序的高级应用)。

  1. 以下关于函数说法错误的是:

    A 函数可以看做是一段具有名字的子程序

    B 对函数的使用必须了解其内部实现原理

    C 函数通过函数名来调用

    D 函数是一段具有特定功能的、可重用的语句组

调用函数不需要知道函数内部实现原理,只需要知道调用方法(即接口)即可。

  1. 哪个选项对于函数的定义是错误的?

    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表示可变参数,可变参数只能放在函数参数的最后。

  1. 关于return语句,以下选项描述正确的是:

    A 函数中最多只有一个return语句

    B return只能返回一个值

    C 函数可以没有return语句

    D 函数必须有一个return语句

函数可以包含0个或多个return语句

  1. 以下关于递归函数基例的说法错误的是:

    A 递归函数必须有基例

    B 递归函数的基例决定递归的深度

    C 递归函数的基例不再进行递归

    D 每个递归函数都只能有一个基例

每个递归函数至少存在一个基例,但可能存在多个基例。

2.程序设计题

  1. 随机密码生成

描述:补充编程模板中代码,完成如下功能:

以整数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))
  1. 连续质数计算

描述:补充编程模板中代码,完成如下功能:

获得用户输入数字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基本语法元素

【笔记】《python语言程序设计》—Python基本图形绘制

【笔记】《python语言程序设计》——基本数据类型

【笔记】《python语言程序设计》——程序的控制结构

【笔记】《python语言程序设计》——函数和代码复用

【笔记】《python语言程序设计》——组合数据类型

【笔记】《python语言程序设计》——文件和数据格式化

【笔记】《python语言程序设计》——程序设计方法学

【笔记】《python语言程序设计》——python计算生态概览

你可能感兴趣的:(【笔记】《python语言程序设计》—函数和代码复用)