CS50P week8 Object-Oriented Programming

本文介绍了Python中元组和列表的区别,以及如何使用类和属性(包括getter和setter)进行数据封装。还讨论了datetime库和inflect库在日期处理中的应用,以及FPDF模块用于生成PDF证书的例子。
摘要由CSDN通过智能技术生成

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:感觉有点类似于私有化属性
  • 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')

难点:

  • 这个参考了其他人的,这玩意参数很奇怪啊,搞不明白
  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值