Lecture 8 - CS50’s Introduction to Programming with Python (harvard.edu)
Notes
tuple(元组)
元组的特性
- 列表定义的时候使用[ ],元组使用( )
- 列表可以改变的,但是元组不可变,也就是元组定义好以后我们不能修改里面的元素
- 能使用元组的尽量使用元组
示例
def main():
student = get_student()
print(f"{student[0]} from {student[1]}")
def get_student():
name = input("Name: ")
house = input("House: ")
return (name, house)
if __name__ == "__main__":
main()
注意:
- 返回多个值时,可以不写括号,返回类型就是一个tuple
示例(返回一个dic)
def main():
student = get_student()
if student["name"] == "Padma":
student["house"] = "Ravenclaw"
print(f"{student['name']} from {student['house']}")
def get_student():
name = input("Name: ")
house = input("House: ")
return {"name": name, "house": house}
if __name__ == "__main__":
main()
Class
class Student:
def __init__(self, name, house):
self.name = name
self.house = house
def main():
student = get_student()
print(f"{student.name} from {student.house}")
def get_student():
name = input("Name: ")
house = input("House: ")
return Student(name, house)
if __name__ == "__main__":
main()
raise
class Student:
def __init__(self, name, house, patronus=None):
if not name:
raise ValueError("Missing name")
if house not in ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]:
raise ValueError("Invalid house")
if patronus and patronus not in ["Stag", "Otter", "Jack Russell terrier"]:
raise ValueError("Invalid patronus")
self.name = name
self.house = house
self.patronus = patronus
def __str__(self):
return f"{self.name} from {self.house}"
def charm(self):
match self.patronus:
case "Stag":
return "🐴"
case "Otter":
return "🦦"
case "Jack Russell terrier":
return "🐶"
case _:
return "🪄"
def main():
student = get_student()
print("Expecto Patronum!")
print(student.charm())
def get_student():
name = input("Name: ")
house = input("House: ")
patronus = input("Patronus: ") or None
return Student(name, house, patronus)
if __name__ == "__main__":
main()
难点:
_init_
:实例化对象__str__
:决定class被调用时的默认返回值
@property
class Student:
def __init__(self, name, house):
self.name = name
self.house = house
def __str__(self):
return f"{self.name} from {self.house}"
# Getter for name
@property
def name(self):
return self._name
# Setter for name
@name.setter
def name(self, name):
if not name:
raise ValueError("Invalid name")
self._name = name
@property
def house(self):
return self._house
@house.setter
def house(self, house):
if house not in ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]:
raise ValueError("Invalid house")
self._house = house
def main():
student = get_student()
print(student)
def get_student():
name = input("Name: ")
house = input("House: ")
return Student(name, house)
if __name__ == "__main__":
main()
注意:
- property:感觉有点类似于私有化属性
- 作用可以看看这个:
- 使方法可以像属性一样被访问
- 防止属性被篡改(
_
)
- Python @property属性详解 setter
- 作用可以看看这个:
- property下是
_house
不是house
:_house
是class自己的,是一个抽象,用户不能直接修改其值,仅出现于@property下的setter
@classmethod
class Student:
def __init__(self, name, house):
self.name = name
self.house = house
def __str__(self):
return f"{self.name} from {self.house}"
@classmethod
def get(cls):
name = input("Name: ")
house = input("House: ")
return cls(name, house)
def main():
student = Student.get()
print(student)
if __name__ == "__main__":
main()
注意:
cls
代表类本身,self
代表类的一个实例对象
继承
class Wizard:
def __init__(self, name):
if not name:
raise ValueError("Missing name")
self.name = name
...
class Student(Wizard):
def __init__(self, name, house):
super().__init__(name)
self.house = house
...
class Professor(Wizard):
def __init__(self, name, subject):
super().__init__(name)
self.subject = subject
...
wizard = Wizard("Albus")
student = Student("Harry", "Gryffindor")
professor = Professor("Severus", "Defense Against the Dark Arts")
...
运算符重载
class Vault:
def __init__(self, galleons=0, sickles=0, knuts=0):
self.galleons = galleons
self.sickles = sickles
self.knuts = knuts
def __str__(self):
return f"{self.galleons} Galleons, {self.sickles} Sickles, {self.knuts} Knuts"
def __add__(self, other):
galleons = self.galleons + other.galleons
sickles = self.sickles + other.sickles
knuts = self.knuts + other.knuts
return Vault(galleons, sickles, knuts)
potter = Vault(100, 50, 25)
print(potter)
weasley = Vault(25, 50, 100)
print(weasley)
total = potter + weasley
print(total)
作业
seasons
seasons.py
from datetime import date
import inflect
import sys
p=inflect.engine()
def main():
print(p.number_to_words(getdate(input("Date of Birth:")),andword="").capitalize(),"minutes")
def getdate(s):
try:
# 转化为规范格式
birth=date.fromisoformat(s)
# date.today()获得今天日期,记住最后返回分钟
return (date.today()-birth).days*24*60
except ValueError:
# 为了退出无异常,选择try&except
sys.exit("Invalid date")
if __name__ == "__main__":
main()
难点:
两个日期之间的时间间隔
- datetime库
- 标准日期格式:
YYYY-MM-DD
(转换函数:date.fromisoformat('20191204')
) date.today()
获得今天日期().days
将结果转化为天数(数字!)
- 标准日期格式:
- inflect库
- 把数字转化为单词:
- 导入库,并
p=inflect.engine()
p.number_to_words(number,andword="")
将number转为文字形式,连接词为空(就没有and)
- 导入库,并
- 把数字转化为单词:
- sys.exit():为了退出无异常,选择try&except
- 句子首字母大写:
.capitalize()
test_seasons.py(懒得写了)
from seasons import getdate
def test_getdate():
assert getdate("1970-01-01")==28504800
assert getdate("2023-03-13")==527040
cookie jar
jar.py
class Jar:
def __init__(self, capacity=12):
self.capacity=capacity
self.remains=0
def __str__(self):
return self.remains*"🍪"
def deposit(self, n):
if self.remains+n<=self.capacity:
self.remains+=n
else:
raise ValueError
def withdraw(self, n):
if self.remains-n>=0:
self.remains-=n
else:
raise ValueError
@property
def capacity(self):
return self._capacity
@capacity.setter
def capacity(self,capacity):
if not capacity or capacity<0:
raise ValueError
self._capacity=capacity
@property
def size(self):
return self.remains
难点:
- @property将capacity和remains私有化
- capacity的设置setter(看其他人也没有用setter,而是在初始化里搞)
test_jar.py
from jar import Jar
import pytest
def test_init():
...
def test_str():
jar = Jar()
assert str(jar) == ""
jar.deposit(1)
assert str(jar) == "🍪"
jar.deposit(11)
assert str(jar) == "🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪🍪"
def test_deposit():
jar = Jar()
with pytest.raises(ValueError):
jar.deposit(20)
jar.deposit(4)
assert jar.size == 4
def test_withdraw():
jar = Jar()
with pytest.raises(ValueError):
jar.withdraw(20)
jar.deposit(3)
jar.withdraw(1)
assert jar.size == 2
shirtificate
from fpdf import FPDF
class PDF(FPDF):
def header(self):
self.set_font('Arial', 'B', 48)
self.cell(0, 30, 'CS50 Shirtificate',align='C')
self.add_image()
def add_text(self, text, font='Arial', size=24, color=(255, 255, 255)):
self.set_text_color(*color)
self.set_font(font, 'I', size)
# 这参数太奇怪了
self.cell(-180, 220, f"{text} took CS50", align='C')
def add_image(self):
self.image("shirtificate.png",10,70,190)
pdf = PDF()
pdf.add_page()
pdf.set_auto_page_break(auto=False, margin=0)
pdf.add_text(input("Name:"))
pdf.output('shirtificate.pdf')
难点:
- 这个参考了其他人的,这玩意参数很奇怪啊,搞不明白