从本章开始,是练习题部分,预计一共有4次题目。通过这四章内容,可以把之前的8章课程内容回顾和总结一下。
1 针对列表的处理和排序
现有如下列表
thisList = ['Otto', 'Level', 'Leseesel', [1, 2, 3], 'Kajak', 'Mueller', 'Retter', 'Rotor', [5, 6, 7], 'Effe', 'Meier']
a) 把列表中的所有元素进行逆序输出:
thisList2 = [x[::-1] for x in thisList]
print(thisList2)
*解析
一般情况下,a[i: j: s] 表示取列表a的第i项到第j-1项,按照步长为s。表示列表的中括号中可以有两个冒号,使用的时候注意冒号的位置。
步长s的取值分正负两种情况:
当s为正数时:把列表从左到右,按照步长为s进行选取,例如 print(a[0: 5: 2])输出的结果是[0, 2, 4]
i的值在默认情况下是0,i总是被包含在输出结果中,例如a[0:5] == a[ :5]
j的值在默认情况下是len(a),也就是列表的长度(5)。j的值不包含在输出结果中,因此a[0: ] 即a[0: 5]可用于输出列表所有元素,因为列表的最大的索引等于列表长度-1。
步长s默认是1,也就是在不指定s的值的情况下,s=1。这也符合我们日常的用法。
当s为负数时:把列表从右往左按照s进行逆序输出。由于方向改变,i的值默认为 -1,也就是最后一个元素;j默认为 -len(a)。
因此采用 a[: : -1]的形式实际上是从列表的最后一个元素向左按照步长s进行选取,也就是逆向输出列表中的每个元素。
回到本例中,我们需要生成一个元素顺序颠倒的列表,因此我们还要在外面套一个中括号(list comprehension)用于生成列表。
这个题当然也能用笨办法做:
thisList2 = []
for item in thisList:
length = len(item) - 1
if type(item) == str:
item2 = ''
while length >= 0:
item2 += item[length]
length -= 1
else:
item2 = []
while length >= 0:
item2.append(item[length])
length -= 1
thisList2.append(item2)
b) 创建另外一个列表,其中的元素是thisList中所有类型为str的元素。
thisList3 = []
for item in thisList:
if type(item) == str:
thisList3.append(item)
print(thisList3)
*解析:这里只需要用if语句对类型进行判断,注意要用==而不是赋值=。此外还要知道怎么判断数据类型,这里我们用了type函数,以下是跟类型相关的函数的辨析:
c) 把以下列表按照每个元组中的数字的和进行降序排序:
evaluations = [('Otto', 3.779, 1.238, 0.49), ('Level', 3.961, 5.725, 0.233), ('Leseesel', 3.935, 1.482, 2.41), ('Kajak', 1.989, 2.66, 0.656), ('Mueller', 2.024, 1.427, 3.013), ('Retter', 3.297, 2.36, 3.179), ('Rotor', 1.733, 4.218, 4.972), ('Effe', 3.311, 3.197, 3.991), ('Meier', 5.956, 2.554, 4.622)]
sortEva = sorted(evaluations, key = lambda x: sum(x[1: ]), reverse=True)
print(sortEva)
print(sortEva[0])
*注意:类似这种情况需要用sorted函数,参数表中的key可以是一个匿名函数。此外sort和sorted的区别在前面的课程里讲过
d) 假设出现这样一种情况,在搜集数据时把格式打乱了,列表中的部分元素也是列表。现在试图修复,把列表中的列表进行解包:
thisList3Corrupted = ['Otto', ['Level', 'Leseesel', 'Kajak'], ['Mueller'], 'Retter', 'Rotor', ['Effe', 'Meier']]
thisList3Repaired = []
for item in thisList3Corrupted:
if type(item) == str:
thisList3Repaired.append(item)
else:
for i in item:
thisList3Repaired.append(i)
print(thisList3Repaired)
上面的方法是将列表中的列表进行遍历,得到元素,然后将该元素append到修复后的列表。append的参数只能是单个元素,这个元素可以是列表,但是不能是多个元素,因此不能用星号来解包。下面尝试用extend方法直接拓展列表,extend方法是将两个列表拼接起来。
thisList3Corrupted = ['Otto', ['Level', 'Leseesel', 'Kajak'], ['Mueller'], 'Retter', 'Rotor', ['Effe', 'Meier']]
thisList3Repaired = []
for item in thisList3Corrupted:
if type(item) == str:
thisList3Repaired.append(item)
else:
thisList3Repaired.extend(item)
print(thisList3Repaired)
2 函数的定义和使用
a)我们注意到,在第一题中使用的列表元素很特殊,有些元素是回文。现在来写一个函数来判断一个列表中的字符串是不是回文,并输出(返回)列表中所有回文元素的索引。
thisList = ['Otto', 'Level', 'Leseesel', [1, 2, 3], 'Kajak', 'Mueller', 'Retter', 'Rotor', [5, 6, 7], 'Effe', 'Meier']
def CheckForPalindroms(list):
index_list = []
for i in range(len(list)):
if type(list[i]) == str:
element = list[i].upper()
if element == element[::-1]:
index_list.append(i)
else:
if list[i] == list[i][::-1]:
index_list.append(i)
return index_list
CheckForPalindroms(thisList)
*注意:通过观察,我们发现列表中既有字符串又有列表,因此需要分情况讨论。此外,python会检查大小写,因此需要将字符串同一转换成大写或小写,否则在判断正序逆序是否相等的时候会出错
b) 写一个函数splitNumber,用于将输入的浮点数分成整数部分和小数部分,并且这两部分要以元组的形式保存。不允许使用python的内置函数。此外,如果输入的不是数字,则这个函数需要输出一个类型错误(ValueError)的Exception。
def splitNumber(num):
try:
int_num = int(num)
dec_num = num - int_num
return(int_num, dec_num)
except ValueError :
print('TypeError: Input has wrong type!')
print(splitNumber(3.56))
print(splitNumber('Hello'))
3 面向对象
这一节针对面向对象编程。学习的时候注意以下几点:
- 类的定义
- 用类构造对象
- 类的成员函数、属性
- 用非成员函数调用类
-
__str()__
函数的定义和触发方式
a) Rectangle类
我们要定义一个长方形类,有如下属性:每个长方形对象的ID,对象的宽度Width,高度Height,面积Area。其中,面积需要通过一个成员函数来计算,这个成员函数直接在 __init()__
函数中调用,并将计算出的面积赋给Area。在该类中还要有一个负责输出长方形对象信息的函数__str()__
,该成员函数会在执行print(长方形对象)时调用,否则直接打印对象,会默认输出对象的地址。
此外还要定义一个函数(非成员函数),Load()
,用于读入一个json文件,并从该json文件包含的信息构造长方形对象,最后把所有对象存放在一个列表中输出。
import json
class Rectangle:
def __init__(self, id, width, height):
# 小写字母来自参数表,大写字母才是类的属性!!
# 想知道构造方法的参数表,可以看一下json文件,也就是我们手头有什么数据可以用于构造对象
self.ID = id
self.Width = width
self.Height = height
# 注意:面积虽然也是属性,但是我们不能把面积写到类的构造方法中去!!
self.Area = self.DetermineArea()
def DetermineArea(self):
area = self.Width * self.Height
return area
# return self.Width * self.Height
def __str__(self):
return f'Rectangle {self.ID} with width {self.Width}, height {self.Height}, area {self.Area}'
# 注意这里不能用print,不然会输出None
def Load(path):
recList = []
with open(path) as file:
data = json.load(file) # data 的类型是字典
for id in data.keys():
rec = Rectangle(id, data[id]['width'], data[id]['height'])
recList.append(rec)
return recList
# 从文件中读入数据
rectangles = Load("Rectangulars.json") # rectangles 的类型是list,元素是长方形对象
# 打印由对象组成的列表,输出一个由对象地址组成的列表
print(rectangles)
# 遍历对象列表并打印,这样才能调用str函数,输出我们想要的信息
for rec in rectangles:
print(rec)
*注意:仔细观察两种输出方式。遍历列表元素(长方形对象)后打印才能得到想要的结果,即:执行str函数
b) 对凯撒密码进行解密
运用当前的技术手段,对这种历史上的传统加密方式进行密码分析是非常容易的。
ciphertext = "Ylmny Buomuozauvy aymwbuzzn! Scjjcy :)"
key = 20
def Decrypt(text, key):
message = '' # 这里是明文,初始化为空字符。python中的str类型可以用加号连接也可以遍历
for sign in text:
if sign >= 'A' and sign <= 'Z': # 判断sign是否位于大写字母A到Z之间
message += chr(ord('A') + ((ord(sign)-ord("A"))-key) % 26)
elif sign >= 'a' and sign <= "z":
message += chr(ord("a")+((ord(sign)-ord("a"))-key) % 26)
else: # sign是特殊符号的情况
message += sign
return message
Decrypt(ciphertext, key)
这是一句德语,意思是第一次作业完成了!耶!