中国大学MOOCPython语言程序设计(北京理工大学)第5-6周学习笔记和课后练习

第5周 函数与代码复用

5.1 函数的定义与使用

使用保留字def定义函数,lambda定义匿名函数
可选参数(赋初值)、可变参数(*b)、名称传递
保留字return可以返回任意多个结果
保留字global声明使用全局变量,一些隐式规则
在这里插入图片描述

5.2 实例7: 七段数码管绘制

理解方法思维
模块化思维:确定模块接口,封装功能
规则化思维:抽象过程为规则,计算机自动执行
化繁为简:将大功能变为小功能组合,分而治之
在这里插入图片描述
基本思路:

 步骤 1:绘制单个数字对应的码管
 步骤 2:获得当前系统时间,变成字符串,绘制对应的码管

思维方法:

 -模块化思维:确定接口,封装功能
 -规则化思维:抽象过程为规则,计算机自动执行
 -化繁为简:将大功能变小组合,分而治之

代码:

# coding:utf-8
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("red")
            turtle.fd(40)
        elif i =="+":
            turtle.write("日",font=("Arial",18,"normal"))
            turtle.pencolor("blue")
        else:
            drawDigit(eval(i))
def main():
    turtle.setup(800,350,200,200)
    turtle.penup()
    turtle.fd(-300)#由绘图中心原点向左300像素
    turtle.pensize(5)
    drawDate(time.strftime("%Y-%m=%d+",time.gmtime()))
    turtle.hideturtle()
    turtle.done()
main()

5.3 代码复用与函数递归

模块化设计:松耦合、紧耦合
函数递归的2个特征:基例和链条
函数递归的实现:函数 + 分支结构

汉诺塔问题

在这里插入图片描述

count=0
def hanoi(n,src,dst,mid):
    global count
    if n==1:
        print("{}:{}>{}".format(1,src,dst))
        count+=1
    else:
        hanoi(n-1,src,mid,dst)
        print("{}:{}>{}".format(n,src,dst))
        count+=1
        hanoi(n-1,mid,dst,src)
hanoi(3,"A","B","C")
print(count)

5.4 模块4: PyInstaller库的使用

PyInstaller库常用参数
参数 描述
-h 查看帮助
–clean 清理打包过程中的临时文件
-D, --onedir 默认值,生成dist文件夹
-F, --onefile 在dist文件夹中只生成独立的打包文件
-i <图标文件名.ico> 指定打包程序使用的图标(icon)文件

5.5 实例8: 科赫雪花小包裹

科赫曲线,也叫雪花曲线
(1) 基本思路:

 -递归思想:函数 +分支
 -递归链条:线段的组合
 -递归基例:初始线段

(2) 分形几何是一种迭代的图,广泛存在于自然界中,请尝试选择一个新曲线绘制:

 -康托尔集、谢宾斯基三角形门格海绵 …
 -龙形曲线 、空间填充科赫…
 -函数递归的深入应用 

代码:

#科赫雪花曲线1一阶
#KochDraw1.py
import turtle
def koch(size,n):
    if n==0:
        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.penup()
    turtle.goto(-350,-50)
    turtle.pendown()
    turtle.pensize(2)
    koch(600,3)
    turtle.hideturtle()
main()

#科赫雪花曲线2 三阶
import turtle
def koch(size,n):
    if n==0:
        turtle.fd(size)
    else:
        for angle in [0,60,-120,60]:
            turtle.left(angle)
            koch(size/3,n-1)
def main():
    turtle.setup(800,600)
    turtle.penup()
    turtle.goto(-200,100)
    turtle.pendown()
    turtle.pensize(2)
    koch(400,level)
    turtle.right(120)
    koch(400,level)
    turtle.right(120)
    koch(400, level)
    turtle.hideturtle()
level=3#也可以直接在题目中设置局部变量
main()
任意累积

注意两个内容:

  1. 无限制数量函数定义的方法,其中b在函数cmul中表达除了a之外的所有输入参数;

  2. 以字符串形式调用函数的方法,"cmul()"与eval()的组合,提供了很多灵活性。

def cmul(a, *b):
    m = a
    for i in b:
        m *= i
    return m
print(eval("cmul({})".format(input())))
斐波那契数列
def fbi(n):
    if n == 1 or n == 2:
        return 1 
    else:
        return fbi(n-1) + fbi(n-2)

n = eval(input())
print(fbi(n))
随机密码生成

在这里插入图片描述

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) 需要对输入小数情况进行判断,获取超过该输入的最小整数(这里没用floor()函数);

(2) 对输出格式进行判断,最后一个输出后不增加逗号(这里没用.join()方法)。

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

第6周 组合数据类型

6.1 集合类型及操作

集合使用{}和set()函数创建
集合间操作:交(&)、并(|)、差(-)、补(^)、比较(>=<)
集合类型方法:.add()、.discard()、.pop()等
集合类型主要应用于:包含关系比较、数据去重

6.2 序列类型及操作

序列是基类类型,扩展类型包括:字符串、元组和列表
列表取反
在这里插入图片描述
在这里插入图片描述
元组用()和tuple()创建,列表用[]和set()创建
元组操作与序列操作基本相同
列表操作在序列操作基础上,增加了更多的灵活性

6.3 实例9: 基本统计值计算

获取多个数据:从控制台获取多个不确定数据的方法
分隔多个函数:模块化设计方法
充分利用函数:充分利用Python提供的内置函数
在这里插入图片描述
注意:
(1) 获取多个数据:从控制台获取逗号分隔的多个数据

(2) 多函数编写方法:模块化设计方法,每部分功能比较清晰

(3) 排序:列表ls的默认排序方法是ls.sort(),如果从大到小排序,用ls.sort(reverse=True)

#基本统计值计算
def getNum():#获取用户不定长输入
    nums=[]
    iNumStr=input("请输入数字(回车退出):")
    while iNumStr!="":
        nums.append(eval(iNumStr))
        iNumStr = input("请输入数字(回车退出):")
    return nums
def mean(numbers):#计算平均值
    s=0.0
    for num in numbers:
        s+=num
    return s/len(numbers)
#计算标准差
def dev(numbers,mean):
    sdev=0.0
    for num in numbers:
        sdev+=(num-mean)**2
    return pow(sdev/(len(numbers)-1),0.5)
#计算中位数
def median(numbers):
    numbers.sort()
    #使用sorted函数必须有返回值
    #或者numbers=numbers.sorted()
    size=len(numbers)
    if size%2==0:
        med=(numbers[size//2-1]+numbers[size//2])/2
    else:
        med=numbers[size//2]
    return med
n=getNum()
m=mean(n)
print("平均值是{},标准差是{:.2},中位数是{}".format(m,dev(n,m),median(n)))

在这里插入图片描述

6.4 字典类型及操作

映射关系采用键值对表达
字典类型使用{}和dict()创建,键值对之间用:分隔
d[key] 方式既可以索引,也可以赋值
字典类型有一批操作方法和函数,最重要的是.get()
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.5 模块5: jieba库的使用

jieba分词依靠中文词库
利用一个中文词库,确定中文字符之间的关联概率
中文字符间概率大的组成词组,形成分词结果
除了分词,用户还可以添加自定义的词组
jieba分词的三种模式:
精确模式、全模式、搜索引擎模式

精确模式:把文本精确的切分开,不存在冗余单词
全模式:把文本中所有可能的词语都扫描出来,有冗余
搜索引擎模式:在精确模式基础上,对长词再次切分

6.6 实例10: 文本词频统计

文本去噪及归一化
中文文本分词
使用字典表达词频
扩展程序解决问题

文本词频统计:英文版哈姆雷特

#calHamletV1.py
def getText():
    txt=open("hamlet.txt","r").read()
    txt=txt.lower()
    for ch in "!#$%&()*+,-./:;<=>?@[\\]^_‘{|}~":
        txt=txt.replace(ch," ")
    return txt

hamletTxt=getText()
words=hamletTxt.split()
counts={}
for word in words:
    counts[word]=counts.get(word,0)+1
items=list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(10):
    word,count=items[i]
    print("{0:<10}{1:>5}".format(word,count))

对中文文本词频统计:

# coding:utf-8
import jieba
txt=open("threekingdoms.txt", "r",encoding="UTF-8").read()
excludes = {"将军","却说","荆州","二人","不可","不能","如此",
            "商议","如何","天下","左右","主公","军马","军士","引兵","次日","东吴"}
#没统计完还有很多词汇需要排除
words=jieba.lcut(txt)
counts={}
for word in words:
    if len(word)==1:
        continue
    elif word == "诸葛亮" or word == "孔明曰":
        rword = "孔明"
    elif word == "关公" or word == "云长":
        rword = "关羽"
    elif word == "玄德" or word == "玄德曰":
        rword = "刘备"
    elif word == "孟德" or word == "丞相":
        rword = "曹操"
    else:
        counts[word]=counts.get(word,0)+1
for word in excludes:
    del counts[word]
items=list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(15):
    word,count=items[i]
    print("{0:<10}{1:>5}".format(word,count))

在这里插入图片描述

课后练习:字典翻转输出

在这里插入图片描述
注意点:
审题,题目说读入一个字典类型的字符串。
字典翻转输出其实是将键值对进行调换,使用 input 函数获取输入,使用eval函数去除引号并赋值给变量 S,这时的变量是获取的字典。随后遍历字典S,并将S的键和值重新赋值给字典dict,其实就是读取现有的字典然后重新创建字典并输出。
如果还是不太理解我们可以将S[i] 这段代码拆分出来,使用 print 语句进行输出,他其实获取的是字典 S 的值,我们将值当做键 dict[S[i]] 然后将键i当做值重新添加到字典 dict 中。

s=input()
try:
    S=eval(s)
    dict={}
    for i in S:
        dict[S[i]]=i
    print(dict)
    
except:
    print("输入错误")

课后练习:《沉默的羔羊》之最多单词

附件是《沉默的羔羊》中文版内容,请读入内容,分词后输出长度大于2且最多的单词。‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬
如果存在多个单词出现频率一致,请输出按照Unicode排序后最大的单词。

# #《沉默的羔羊》之最多单词
import jieba
f=open("沉默的羔羊.txt","r",encoding="UTF-8").read()
words=jieba.lcut(f)
counts={}
for word in words:
    counts[word]=counts.get(word,0)+1
maxc = 0
maxw = ""
for k in words:
    if counts[k] > maxc and len(k) > 2:
        maxc = counts[k]
        maxw = k
    if counts[k] == maxc and len(k) > 2 and k > maxw:
        maxw = k
print(maxw)

单元测试程序题

1.数字不同数之和

描述
获得用户输入的一个整数N,输出N中所出现不同数字的和。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬
例如:用户输入 123123123,其中所出现的不同数字为:1、2、3,这几个数字和为6。

使用集合的去重功能!

N=input()
s=set(N)
sum=0
for i in s:
    sum+=eval(i)
print(sum)

2.人名最多数统计

描述
编程模板中给出了一个字符串,其中包含了含有重复的人名,请直接输出出现最多的人名。

#2.人名最多数统计
# #编程模板中给出了一个字符串,其中包含了含有重复的人名,请直接输出出现最多的人名。
s = '''双儿 洪七公 赵敏 赵敏 逍遥子 鳌拜 殷天正 金轮法王 乔峰 杨过 洪七公 郭靖
       杨逍 鳌拜 殷天正 段誉 杨逍 慕容复 阿紫 慕容复 郭芙 乔峰 令狐冲 郭芙
       金轮法王 小龙女 杨过 慕容复 梅超风 李莫愁 洪七公 张无忌 梅超风 杨逍
       鳌拜 岳不群 黄药师 黄蓉 段誉 金轮法王 忽必烈 忽必烈 张三丰 乔峰 乔峰
       阿紫 乔峰 金轮法王 袁冠南 张无忌 郭襄 黄蓉 李莫愁 赵敏 赵敏 郭芙 张三丰
       乔峰 赵敏 梅超风 双儿 鳌拜 陈家洛 袁冠南 郭芙 郭芙 杨逍 赵敏 金轮法王
       忽必烈 慕容复 张三丰 赵敏 杨逍 令狐冲 黄药师 袁冠南 杨逍 完颜洪烈 殷天正
       李莫愁 阿紫 逍遥子 乔峰 逍遥子 完颜洪烈 郭芙 杨逍 张无忌 杨过 慕容复
       逍遥子 虚竹 双儿 乔峰 郭芙 黄蓉 李莫愁 陈家洛 杨过 忽必烈 鳌拜 王语嫣
       洪七公 韦小宝 阿朱 梅超风 段誉 岳灵珊 完颜洪烈 乔峰 段誉 杨过 杨过 慕容复
       黄蓉 杨过 阿紫 杨逍 张三丰 张三丰 赵敏 张三丰 杨逍 黄蓉 金轮法王 郭襄
       张三丰 令狐冲 赵敏 郭芙 韦小宝 黄药师 阿紫 韦小宝 金轮法王 杨逍 令狐冲 阿紫
       洪七公 袁冠南 双儿 郭靖 鳌拜 谢逊 阿紫 郭襄 梅超风 张无忌 段誉 忽必烈
       完颜洪烈 双儿 逍遥子 谢逊 完颜洪烈 殷天正 金轮法王 张三丰 双儿 郭襄 阿朱
       郭襄 双儿 李莫愁 郭襄 忽必烈 金轮法王 张无忌 鳌拜 忽必烈 郭襄 令狐冲
       谢逊 梅超风 殷天正 段誉 袁冠南 张三丰 王语嫣 阿紫 谢逊 杨过 郭靖 黄蓉
       双儿 灭绝师太 段誉 张无忌 陈家洛 黄蓉 鳌拜 黄药师 逍遥子 忽必烈 赵敏
       逍遥子 完颜洪烈 金轮法王 双儿 鳌拜 洪七公 郭芙 郭襄 赵敏'''

#传统解法,先使用字典建立"姓名与出现次数"的关系,然后找出现次数最多数对应的姓名。
#初始化空字典
dict={}
#将字符串分割
words=s.split()
#对字典中元素进行遍历
for i in words:
    dict[i]=dict.get(i,0)+1
max_name,max_cnt="",0
#遍历字典
for k in dict:
    if dict[k] > max_cnt:
        max_name,max_cnt=k,dict[k]
print(max_name)

#还有一个方法简洁点
#将结果用列表表示,每一项都是一个元组,存放key和value
#result=list(dict.items())
#也可以使用sort函数排序
#result.sort(key=lambda x:x[1],reverse=True)
#print(result[0][0])
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值