初识python(下)(基于苏州大学慕课网)

初识python(下)

5函数与应用

函数与问题分而治之

函数结构

def 函数名 ([参数列表]):
	函数体

例子:

def prime(x):
	if x<2:
		return False
	for k in range(2,int(math.sqrt(x)+1)):
		if x%k == 0:
			return False
	return True

问题:文件中有多个日期格式的数据,一行一个,输出其中合法的日期数据。
读取文件

def read_file(fn):
	f = open(fn,"rt") #打开文件
	data = f.readlines() #读取文件
	f.close() #关闭文件 
	return data

#判断日期合法性代码参考上一篇文章内容

输出

def display(data):
	for item in data:
		if legal_date(item): #判断日期是否合法函数
			print(item, end="")

主体程序

if __name__ == '__main__': 
	display(read_file("test.txt"))

主体程序中的if语句的作用是: 当该python文件被其它文件import时不会执行,因为任意python文件中,__name__等于’__main__’。而被import时,该文件中输出的__name__则为文件名。

基于函数验证哥德巴赫猜想

def isPrime(n):
	#.....参考上篇文章,或导入他人编写的高效算法
	#import sympy
	#sympy.isprime(123456761)
def goldbach(n):
	if n < 2 or n % 2 == 1:
		print(n, '不是一个大于2的偶数')
		return
	for p in range(2, n):
		if isPrime(p) and isPrime(n - p):
			print(n, '=', p, '+', n - p)
			return
	print('哥德巴赫猜想好像有问题!')
def test_goldbach():
	n = int(input("请输入一个大于2的偶数,或者输入0退出:"))
	while n != 0:
		goldbach(n)
		n = int(input("请输入一个大于2的偶数,或者输入0退出:"))

十进制转二进制

方法一:

#python内置的函数bin可以将参数转换为二进制并返回
bin(19) #0b10011 
#将一个数值的字符串转换成一个十进制整数,第二个参数指定进制
int('10011',2) #19

方法二:

def my_bin(n):
	L = []
	if n < 0: #考虑负数情况
		n *= -1
		L.append('-')
	v = 1
	while v <= n // 2:
		v *= 2
	while v > 0:
		if n < v:
			L.append('0')
		else:
			L.append('1')
			n -= v
		v //= 2
	return ''.join(L)

思考题:

  • 编写函数my_hex(n),将十进制整数n转换成十六进制数
  • 编写函数hex2bin(n),将十六进制数n转换成二进制数
    • 思路1:先将十六进制转换成十进制,再调用my_bin转成二进制
    • 思路2:直接将十六进制转换成二进制

多种方法求圆周率

第一种 莱布尼兹级数法

PI = 3.141592654
base = 1

for k in range(1, 8):
	base *= 10
	pi = 0
	tm = 1
	for i in range(0, base):
		pi += tm / (2 * i + 1)
		tm = -tm
	pi *= 4
	print("%d\tpi=%.7f\t误差率(x10000)=%.5f" % (k,pi,abs(pi - PI) / PI * 10000))
```s

第二种 蒙特卡罗法
```python
import random
PI = 3.141592654
def gen_pi():
	count, max_c = 0, 10000000
	for i in range(0, max_c):
		x, y = random.random(), random.random()
		if x*x + y*y <= 1:
			count += 1
	return (count / max_c * 4)

if __name__ == '__main__':
	sum_dif, k = 0, 20
	for i in range(k):
		pi = gen_pi()
		dif = abs(pi - PI) / PI * 10000
		sum_dif += dif
		print("%d\tpi=%.7f\t误差率(x10000)=%.3f" % (i+1,pi,abs(pi - PI) / PI * 10000))
	print("平均误差率(x10000)=%.3f" % (sum_dif / k))

关于random函数的介绍

Base64编码

在这里插入图片描述
在这里插入图片描述

递归思想和递归函数

例:求阶层
def factorial(n):
	if n == 1:
		return 1
	else :
		return n * factorial(n - 1)
例:计算列表中最大值
def my_max(L):
	if len(L) == 1:
		return L[0]
	else:
		return max(L[0], my_max(L[1:]))
		#L[x:]表示从前截掉x个元素
		#L[:x]表示从前截取x个元素
		#L[a:b]表示从前截取b个再截掉a个
		#L[:-x]表示从后截掉x个元素
		#L[-x:]表示从后截取x个元素
例:斐波那契数列
def fibonacci(n):
	if n <= 1:
		return n
	else:
		return fibonacci(n-1) + fibonacci(n-2)

递归的不足:

效率低下:函数的多次调用
改进斐波那契的递归方法

思路:F(n-1)的计算过程中已经知道了F(n-2)的值,直接在F(n)的计算中利用该值,避免重复计算。

def good_fibonacci(n):
	if n <= 1:
		return (n, 0)
	else:
		(a, b) = good_fibonacci(n-1)
		return (a+b, a)

车队的公共钥匙盒

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解法1

• 首先对K条记录排序
第一排序条件:返还时刻
第二排序条件:钥匙编号
• 生成时刻列表
得到所有的借用时刻、返还时刻
将上述时刻放到一个列表中去重并排序
• 利用时刻列表构造循环
还钥匙,并发还,则按照钥匙编号从小到大还
借钥匙,并发借,不会影响最终结果

#获取输入函数
def getInput():
	keyCount, rowCount = map(int, input().split())
	#map(func, iterable, ...)
	#第一个参数func以参数序列中的每一个元素调用func函数,返回包含每次func函数返回值的新列表。
	keys = [i for i in range(1,keyCount+1)] #初始化钥匙盒
	datas = []
	for i in range(rowCount): #借还记录
		datas.append(list(map(int,input().split())))
	return keys,datas
#预处理函数
def preProcess(datas):
	for item in datas: #得到返还时刻
		item[2] = item[1] + item[2]
	datas.sort(key = lambda temp : (temp[2],temp[0]))
	times = sorted(set([item[1] for item in datas])
				| set([item[2] for item in datas]))
	return datas, times
#模拟借还的函数
def process(times,keys,datas):
	for time in times:
		for item in datas: #返还
			if item[2] == time:
				keys[keys.index(0)] = item[0]
				item[2] = -1
			elif item[2] > time:
				break
		for item in datas: #借
			if item[1] == time:
				keys[keys.index(item[0])] = 0
				item[1] = -1
	return keys
	
if __name__ == '__main__':
	(keys, datas) = getInput()
	(datas, times) = preProcess(datas)
	print(process(times,keys,datas))
解法2

• 每一条借还记录包括借操作和还操作
借的时刻在前
还的时刻在后
因此模拟时一条数据要被处理两次
• 直接把一条记录拆分成两条记录
钥匙编号 时刻 借操作
钥匙编号 时刻 还操作
• 不再需要times列表

keyCount, rowCount = map(int,input().split())
keys = [i for i in range(1, keyCount + 1)]
datas = []
for i in range(rowCount):
	temp = list(map(int, input().split()))
	datas.append([temp[0],temp[1],1]) #借记录
	datas.append([temp[0],temp[1]+temp[2],2]) #还记录
datas.sort(key = lambda temp : (temp[1], -temp[2], temp[0]))
for item in datas:
	if item[2] == 1:
		keys[keys.index(item[0])] = 0
	else:
		keys[keys.index(0)] = item[0]
for item in keys:
	print(item, end=" ")

练习题

1.在函数中yield语句的作用和return完全一样。(×)
补充内容:return和yield的区别
2.每个return语句只能返回一个值。(×)
3.定义函数时,带有默认值的参数必须出现在参数列表的最右端,任何一个带有默认值的参数右边不允许出现没有默认值的参数。(√)
4.在定义函数时,某个参数名字前面带有一个*符号表示可变长度参数,可以接收任意多个普通实参并存放于一个元组之中。(√)
5.在定义函数时,某个参数名字前面带有两个*符号表示可变长度参数,可以接收任意多个关键参数并将其存放于一个字典之中。(×)
6.Python不仅允许函数嵌套调用,还允许函数嵌套定义。(√)
7.如下代码被执行,运行结果是语法错误

print(get_max(3,5)) #应当在函数定义后调用函数
def get_max(num1,num2):
	return num1 if num1>num2 else num2

8.如下程序的运行结果是 [100,2,3]

def exchange(lst):
    lst[0]=100
lst=[1,2,3]
exchange(lst)
print(lst)

9.如下程序的运行结果是 [1,2,3]

def exchange(lst):
    lst=[4,2,3]
lst=[1,2,3]
exchange(lst)
print(lst)

10.在函数内没有办法定义全局变量。(×,global可以)
11.在函数内部直接修改形参的值并不影响外部实参的值。(×)
12.在同一个作用域内,局部变量会隐藏同名的全局变量。(√)
13.如下程序的输出结果是 50 100 100

def myfun(x,y=200,z=100):
    print(x,y,z)
myfun(50,100)

14.如下程序的输出结果是 (1,2,3)

def myvar1(*t):
    print(t)
myvar1(1,2,3)

15.如下程序的输出结果是 25

def fun():
    return lambda x,y:x*x+y*y
fx=fun() #没有这句会报错
print(fx(3,4))

16.如下代码使用了math模块中的sqrt,为了使得该代码正确,需要使用import,请给出和本次调用相适配的import的完整指令。(from math import sqrtfrom math import * )

print(sqrt(3.5))

17.如下函数的返回值是。([2,5,8]

def test():
    temp=[1,2,3,4,5,6,7,8,9,10]
    return [x for x in temp if x%3==2]

18.如下函数的返回值是。(
[(1, 4), (2, 5), (3, 6)])

def test():
    l1=[1,2,3]
    l2=[4,5,6]
    return list(zip(l1,l2))

19.如下代码的输出结果是_________

def number1Bit(x):
    count = 0
    while x:
        count = count + 1
        x = x & (x-1)
    return count
print(number1Bit(17))

答:2。

&运算,按位取值,同为1则取1,否则取0
^=,异或运算,按位取值,不同取1,否则取0
&=,与运算赋值,按位取值,同为1则取1,否则取0
|=,或运算,按位取值,只要有一方为1则取1,否则取0

20.如下代码的输出结果是。(3 5

a,b=5,3
a ^= b
b ^= a
a ^= b
print(a,b)

21.如下程序的运行结果是 (olleh

def func(str1):
    if len(str1)==1 or len(str1)==0:
        return str1
    else:
        return str1[-1]+func(str1[:-1])
print(func("hello"))

22.如下程序的运行结果是 (3 2 6

def fact(num):
    ret=0;
    if(num<=1):
        ret=1;
    else:
         print(num,end=' ')
        ret=num*fact(num-1)
    return ret
print(fact(3))

23.如下程序的运行结果是 (6)

def lengthOfLastWord(sstr):
        for word in sstr.split()[::-1]:
            return len(word)
        return 0
print(lengthOfLastWord("i like python"))
#sstr.split()是将sstr按空格切割成元组
#words[::-1]是返回倒置元素顺序后的words

#该代码 sstr.split()[::-1]
#实际上等价于列表['python','like','i']
#而遇return结束函数运行
#所以仅返回第一个元素的长度,即len('python')

24.如下代码的运行结果是 ([[1, 4], [2, 5], [3, 6]])

def transpose(lst):
    test = [[0 for i in range(len(lst))] for j in range(len(lst[0]))]
    #test = [[0,0],[0,0],[0,0]]
    #len(lst) = 2, len(lst[0]) = 3
    for i in range(len(lst)):
        for j in range(len(lst[i])):
            test[j][i]=lst[i][j]
    return test
print(transpose([[1,2,3],[4,5,6]]))

25.如下程序的运行结果是。((4,6,3,0))

def statistics(str1):
    num = 0
    isah = 0
    kong = 0
    other = 0
    for i in str1 :
        if i.isdigit(): #是否为数字
            num +=1
        elif i.isalpha(): #是否为字母
            isah +=1
        elif i.isspace(): #是否为空格
            kong +=1
        else:
            other +=1
    return num,isah,kong,other
print(statistics(' das1 32 a2da'))

26.如下程序的运行结果是 [2, 4, 3, 1]

def sortArrayByParity( lst):
    lst.sort(key=lambda t: t%2)
    return lst   
lst=[3,1,2,4]
sortArrayByParity(lst)
print(lst)

27.x = {1:2, 2:3, 3:4},则sum(x)的值为。(6
sum(x.values())的值为。(9
28.x = {i: str(i+3) for i in range(3)},得到的x是什么?({0: ‘3’, 1: ‘4’, 2: ‘5’}
sum(item[0] for item in x.items())的值为。(3

6文件

读文本文件
1)read([size])  size 未指定则返回整个文件
2)readline() 读取一行
3)readlines([size]) 返回包含size行的列表, size 未指定则返回全部行
写文本文件
1)write()  将字符串写入文件
2)writelines() 将列表种的字符串写入到文件
自动关闭文件的写法
	with open(文件名,打开方式) as 别名:
		别名.文件读写函数
其它
1)f.tell():返回一个整数,表示当前文件指针的位置(就是到文件头的字节数)。
2)f.seek(偏移量,[起始位置]):用来移动文件指针。
偏移量: 单位为字节,可正可负
起始位置: 0-文件头(默认);1-当前位置; 2-文件尾
3)for line in f: print line :通过迭代器访问。

一个例子:简易英汉字典

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

文件加密解密

1维吉尼亚加密法
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def encrypt(msg, key):
	return translate_msg(msg, key, 'encrypt')

def decrypt(msg, key):
	return translate_msg(msg, key, 'decrypt')

def translate_msg(msg, key, mode):
	cipher = []
	key_index = 0
	key = key.upper()
	for c in msg:
		num = LETTERS.find(c.upper())
		if num != -1:
			 if mode == 'encrypt':
			 	num += LETTERS.find(key[key_index])
			 elif mode == 'decrypt':
			 	num -= LETTERS.find(key[key_index])
			 num %= len(LETTERS)
			 if c.isupper():
			 	cipher.append(LETTERS[num])
			 else:
			 	cipher.append(LETTERS[num].lower())
			 key_index += 1
			 if key_index == len(key):
			 	key_index = 0
		else:
			 cipher.append(c)
	return ''.join(ciper)

加密文本文件

#加密
def encrypt_file(src_file, des_file, key):
	src_file_obj = open(src_file)
	msg = src_file_obj.read()
	src_file_obj.close()
	msg_en = encrypt(msg, key)
	des_file_obj = open(des_file, 'w')
	des_file_obj.write(msg_en)
	des_file_obj.close()

#解密
def decrypt_file(src_file, des_file, key):
	src_file_obj = open(src_file)
	msg = src_file_obj.read()
	src_file_obj.close()
	msg_de = decrypt(msg, key) #与加密方法仅此一处不同
	des_file_obj = open(des_file, 'w')
	des_file_obj.write(msg_de)
	des_file_obj.close()

练习题

1.使用函数open()打开文件时,如果没有在参数中指定模式,则默认的模式为 ‘a+’。(×,默认为’r’
2.使用open()函数以’w’模式打开文件进行写入操作时,如果原文件中有内容,则会被新写入的内容覆盖掉。(√)
3.read方法只能一次性读取文件中的所有数据。(×)
4.在Linux系统中,用于读取当前目录下的data目录中的file.txt文件的是(with open(‘data/file.txt’, ‘r’) as f:)
5.在Windows系统中,用于读取当前目录下的data目录中的file.txt文件的是(with open(‘data\file.txt’, ‘r’) as f:)
6.如果文件不存在,哪一种打开方式会报错?(‘r’
7.文件对象的____方法用于将缓冲区的内容写入文件,但是不关闭文件。(flush
8.如果首先以读模式打开一个文件,然后用seek方法把文件指针定位到文件的最后,再通过tell方法就可以得到一个文件的长度。(√)
9.write方法用于把字符串写入文本文件并在最后添加换行符。(×)
10.使用函数open()打开文件时,如果没有指定编码方式(即encoding),则该参数默认值总为’utf-8’。(×,在 Windows 简体中文版中默认编码是 ‘cp936’ 或 ‘gbk’ (在 python 执行环境中,将 MS936 ,CP936,gbk 视为同一套编码))
11.以写模式(‘w’)打开的文件无法进行读操作。(√)
12.如果文件a.txt中内容为空,则下面程序输出内容为None。(×)

with open('a.txt', encoding='utf-8') as f:
    if not f:
        print('None')

7异常处理

异常处理与程序健壮性

Python用于异常处理的关键字
try 监视异常
raise 抛出异常
except 捕获异常 #可以有多个
else 异常没有发生时
finally 异常收尾

一个完备的异常处理器

try:
	语句块
execept 异常类型1[ as 错误描述]: #例:except ZeroDivisionError:(除数为0异常)
	异常处理语句块1
……
execept 异常类型n[ as 错误描述]:
	异常处理语句块n
execept:
	默认异常处理语句块
else:
	语句块
finaly:
	语句块

错误处理的几条原则

  • 程序遇到错误情况时还能以某种方式执行下去
    • 不随意终止执行
    • 不崩溃
  • 遇到错误时,不出现任意的非预期行为
    • 任何时候的行为都符合预期
  • 在某个局部发生错误时,尽可能局部处理
    • 不处理的异常将触底给父函数(主调函数)

异常处理的实际应用

常见异常

NameError 标志名错误
SyntaxError 语法错误
IndexError 索引错误
TypeError 类型错误
KeyError 键错误
ValueError 值异常
在这里插入图片描述
在这里插入图片描述

值域异常
def get_age():
	while True:
		try:
			num = int(input("请输入您的年龄(18-60)")
			if num < 18 or num > 60:
				raise -1 #抛出异常可被'except int:'捕获
			else:
				return num
		except ValueError:
			print("请输入一个整数!")
		except int: #捕获raise -1抛出的异常
			print("您的输入不合法!")

利用异常跳出多重循环

try:
	for i in range(10):
		for j in range(i):
			if i + j > 5:
				raise -1
except:
	print(i, j)
八皇后问题

在这里插入图片描述
在这里插入图片描述

小结

• 良好的异常可以大大提高程序的健壮性和容错性
在涉及到申请和释放资源时一定要使用异常确保资源被释放(打开关闭文件、数据库)
• 异常是可以嵌套的
内部捕获以及处理的异常不会向外抛出
内部不捕获的异常会往外抛出
• Python各种异常的基类是BaseException
可以创建用户自定义异常类

练习题

1.Python内建异常类的基类是。(BaseException
2.一条except语句可以包含多个异常。(√)
3.如果一个函数func中的代码引发了异常,且该函数无处理异常的代码,那么该异常将会传递到调用func函数的地方。(√)
4.一个except后面紧跟着冒号,表示可以捕获任意类型的异常。(√)
5.使用异常可以避免程序出现逻辑错误。(×)
6.如下程序运行后如果输入5,a ,那么运行结果是。(程序出错

def main():
    a,b=eval(input()) #此处出错
    try:
        s=a/b
        print(s)
    except:
        print("Divide 0!")
main()

7.在捕获到异常时,如果不想处理异常,而是让程序继续运行下去,可以使用pass语句。(√)
8.Python中,对于代码中的每个try,必须至少有一个except与它匹配。(×)
9.使用________关键字,可以保证之后的代码块无论是否发生异常,一定会被执行。(finally

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值