摆烂了两三天,然后才开始看IO操作,这节课还是蛮有意思的,处理csv文件和with语句都大有帮助,但是我就是为什么看不下去呢o(╥﹏╥)o
1 Lines of Code.py
Q:怎么检测一个py文件的有效行数,不算空行和注释
- 对于这道题:得先判断文件存不存在,如果不存在就sys.exit()退出
- 文件是不是以py为结尾(这里可以用切片,也可以用split(),但是用split比较好,用切片的话文件以.spy之类的结尾你该怎么办呢)
- 怎么判断是不是空白行呢?还记得rstrip()吗,可以去除字符串末尾的指定字符,只要rstrip()是"",那么就说明没有内容
- 对于注释行,我们可以用.lstrip()去除前面的空白后判断第一个是不是#
所以代码的核心就是这样:
# 如果字符最后两个不是py
if sys.argv[1].split(".")[-1] == "py":
with open(f"{sys.argv[1]}", "r") as file:
for line in file:
# 如果该行有内容的话且不是#的话
if line.rstrip() != "" and line.lstrip()[0] != "#":
lines += 1
完整代码:github
2 Pizza Py.py
Q:将一个csv文件的内容以tabulate的ASCII艺术形式打印出来,也就是打印给你的csv菜单文件打印出来
+------------------+---------+---------+
| Sicilian Pizza | Small | Large |
+==================+=========+=========+
| Cheese | $25.50 | $39.95 |
+------------------+---------+---------+
| 1 item | $27.50 | $41.95 |
+------------------+---------+---------+
| 2 items | $29.50 | $43.95 |
+------------------+---------+---------+
| 3 items | $31.50 | $45.95 |
+------------------+---------+---------+
| Special | $33.50 | $47.95 |
+------------------+---------+---------+
- 很幸运, tabulate没有多少方法和函数,你只要print(tabulate(table, headers, tablefmt="grid"))就行,但是怎么拿到table和headers呢?
- 对于headers,我们可以用csv库已字典形式拿出第一行,也就是执行一次遍历文件行的for循环,获得了它的键,然后再将值添加到table中。如果你这里不添加值到table的话后面就reader不会遍历到第一行的值。由于是字典,所以还得转化成列表
with open(f"{sys.argv[-1 ]}", "r") as file:
# 只接受列表里面的内容[[ss,ss],[as,sa]]
reader = csv.DictReader(file)
for cow in reader:
# 这里获得的只是键,但是又获得了一个值,所以得再添加一个值到table
headers = cow.keys()
cow_list = cow.values()
table.append(list(cow_list))
break
对于table,获得值就行,记得转换
for cow in reader:
#cow是字典,下面是为了获得字典的值,因为cow会直接输出第一二个的值然后一一映射
cow_list = cow.values()
table.append(list(cow_list))
Scourgify.py
Q:类似于下面的csv文件,怎么把它的name分为First和last,然后写入和house另一个csv文件中
name,house
"Abbott, Hannah",Hufflepuff
"Bell, Katie",Gryffindor
"Bones, Susan",Hufflepuff
"Boot, Terry",Ravenclaw
- 其实考验的是怎么使用csv这个库写入内容,有了前面reader的基础,我们很容易就想到要获得name可以,这样就有First,last,和house
with open(sys.argv[1], "r") as file1:
reader = csv.DictReader(file1)
# field是第一行的name,也就是第一行的内容
# 这里line的内容是由name和house构成的,获取name的值然后分开
for line in reader:
first, last = line["name"].split(",")
house = line["house"]
- 写入的话要使用DictWriter ,可以搜搜语法,怎么写入列表标题,所以核心就是这样:
with open(sys.argv[1], "r") as file1, open(sys.argv[2], "w") as file2:
reader = csv.DictReader(file1)
# field是第一行的name,也就是第一行的内容
writer = csv.DictWriter(file2, fieldnames=["first", "last", "house"])
# 写入列名(字段名)
writer.writeheader()
# 这里line的内容是由name和house构成的,获取name的值然后分开
for line in reader:
first, last = line["name"].split(",")
house = line["house"]
# 去除空格
last = last.strip()
writer.writerow({"first": last, "last": first, "house": house})
完整代码:github
CS50 P-Shirt.py
Q:给你两张图片![](https://img-blog.csdnimg.cn/direct/a4b2e64eca724c649acced881bcb7e45.png)
,要变成下面这样![](https://img-blog.csdnimg.cn/direct/b812fef32a494c1d888f15bb812a63fb.png)
- 这里给我们提示用PIL这个库,它提供四个函数和一个方法可以帮我们完成这个事情
-
Image.open("shirt.png"),打开图片做处理,返回一个Image类型
-
获取像素大小 size = shirt.size(接受一个Image对象)
-
裁剪函数,让两个图片一样大小PIL.ImageOps.fit(image, size)
-
覆盖,让一张图片覆盖另一张:被覆盖图片.paste(覆盖图片,覆盖起始位置,mask=要保留透明通道的图片),就是是否继续让文件保留透明形式,mask是要保留的图片)
-
保存函数:保存处理后的图片save(名字)
所以核心代码这样
if len(sys.argv) == 3:
# 获得后缀
def suffix(x): return x.split(".")[-1]
# 两个文件的后缀不相同
if suffix(sys.argv[1]) != suffix(sys.argv[2]):
sys.exit("Input and output have different extensions")
# 如果第二个后缀不是图片
if suffix(sys.argv[2]) not in ("jpg", "png", "jepg"):
sys.exit("Invalid output")
# 如果字符最后是图片格式
if suffix(sys.argv[1]) in ("jpg", "png", "jepg"):
shirt = Image.open("shirt.png")
before = Image.open(sys.argv[1])
# 获取像素大小
size = shirt.size
# 裁剪,把目标裁剪成跟shirt图像一样大小
before = PIL.ImageOps.fit(before, size)
# 覆盖,shirt覆盖before,保留透明通道
before.paste(shirt, (0, 0), mask=shirt)
before.show()
# 保存处理后的图像
before.save(sys.argv[2])
本周的作业难度适中,考验的是对一些库的方法和函数的使用,祝大家天天开心(*^▽^*)