
零基础学Python:Day11!类和对象:面向对象编程入门
昨天我们学习了Python中模块和包的使用,学会了怎么组织代码和复用别人写好的功能。老规矩,先公布昨天的作业答案,看看你都做对了没~
📋 昨日作业答案
1. 自定义一个模块utils.py,在里面写两个函数:一个判断偶数(输入整数返回True/False),一个计算列表所有偶数的和,然后在main.py中导入这个模块,测试你的函数
utils.py模块内容:
# utils.pydef is_even(num):"""判断一个数是不是偶数"""return num % 2 == 0def sum_even_list(num_list):"""计算列表中所有偶数的和""" total = 0for num in num_list:if is_even(num): total += numreturn totalmain.py导入测试:
# main.pyimport utilsprint(utils.is_even(4)) # Trueprint(utils.is_even(7)) # Falsetest_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]print(f"列表中偶数的和:{utils.sum_even_list(test_list)}") # 输出:2+4+6+8+10 = 30就是这么简单,模块拆分后逻辑清晰,导入就能用,你写对了吗?
2. 使用random模块实现一个猜数字游戏:程序随机生成一个1-100之间的数字,让用户猜,用户输入数字后,提示猜大了还是猜小了,直到猜对为止,最后统计猜了多少次
import random# 生成随机数secret_num = random.randint(1, 100)guess_count = 0print("欢迎来到猜数字游戏!我生成了一个1-100之间的整数,你来猜猜看~")while True: user_input = input("请输入你猜的数字:") guess_count += 1try: guess = int(user_input)except ValueError:print("请输入合法的整数!")continueif guess < 1 or guess > 100:print("请输入1-100之间的数字!")continueif guess == secret_num:print(f"恭喜你猜对了!你一共猜了{guess_count}次")breakelif guess > secret_num:print("猜大了,再小一点")else:print("猜小了,再大一点")运行起来就能玩了,很有趣的小游戏,用到了我们之前学的循环和异常处理,逻辑非常清晰。
3. 使用datetime模块计算距离你下一个生日还有多少天
from datetime import datetime, timedelta# 输入你的生日,月-日格式birthday_input = input("请输入你的生日(格式:MM-DD,比如08-15):")birthday_month, birthday_day = map(int, birthday_input.split("-"))today = datetime.now()current_year = today.year# 计算今年生日日期this_year_birthday = datetime(current_year, birthday_month, birthday_day)# 如果今年生日已经过了,就计算明年生日if today > this_year_birthday: next_birthday = datetime(current_year + 1, birthday_month, birthday_day)else: next_birthday = this_year_birthdaydelta = next_birthday - todayprint(f"距离你的下一个生日还有:{delta.days}天")代码处理了生日已经过了的情况,自动计算明年的生日,非常贴心,你可以自己试试,输入你的生日看看结果~
4. 创建一个包my_tools,里面放两个模块string_utils.py和math_utils.py,分别放几个字符串工具函数和数学工具函数,然后在主程序中导入包里面的模块并使用
首先创建项目目录结构:
project/├── main.py└── my_tools/ ├── __init__.py ├── string_utils.py └── math_utils.pystring_utils.py(字符串工具模块):
# my_tools/string_utils.pydef reverse_str(s):"""反转字符串"""return s[::-1]def is_palindrome(s):"""判断是不是回文串"""return s == reverse_str(s)math_utils.py(数学工具模块):
# my_tools/math_utils.pydef factorial(n):"""计算n的阶乘""" result = 1for i in range(1, n+1): result *= ireturn resultdef gcd(a, b):"""计算两个数的最大公约数"""while b: a, b = b, a % breturn a__init__.py可以是空文件,或者导出函数方便导入。
然后在main.py导入使用:
# main.pyfrom my_tools import string_utils, math_utilsprint(string_utils.reverse_str("Hello")) # olleHprint(string_utils.is_palindrome("abba")) # Trueprint(math_utils.factorial(5)) # 120print(math_utils.gcd(12, 18)) # 6完美,包和模块都创建成功,导入使用正常,你掌握了包的使用了吗?
对完答案,我们开始今天的正题:类和对象,面向对象编程!到今天为止,我们之前写的代码都是面向过程的,也就是一步一步按顺序写,执行完就结束。而面向对象是另一种编程思想,它把数据和操作数据的方法绑定在一起,更适合开发大型项目,代码更容易维护和扩展。
面向对象是Python非常核心的知识点,几乎所有Python库都是基于面向对象实现的,所以一定要掌握它,我们今天就从入门开始,一步步带你理解!
🤔 什么是类?什么是对象?
可能你第一次听说"类和对象",感觉有点抽象,我们用生活中的例子来理解,就非常简单了:
类(Class):是一个模板,抽象的描述,比如"猫"这个类别,就是一个类,它描述了所有猫共有的特征和行为 对象(Object):是根据模板创建出来的具体实例,比如你家里那只叫"橘橘"的猫,就是一个具体的对象
我们再举个例子:
类:"汽车",描述了汽车都有颜色、品牌、速度这些属性,都有启动、加速、刹车这些行为 对象:你楼下那辆红色特斯拉Model 3,就是一个具体的汽车对象
一句话总结:类是模板,对象是模板造出来的具体东西,一个类可以造出无数个对象。
面向对象编程就是这么来的,我们用类描述事物共有的属性(特征)和方法(行为),然后创建具体的对象来使用,非常符合我们人类认识世界的方式。
Python中定义类和创建对象
Python中定义类用class关键字,基本语法:
class 类名:# 初始化方法,创建对象的时候自动调用def __init__(self, 参数1, 参数2):self.属性1 = 参数1self.属性2 = 参数2# 定义方法(行为)def 方法名(self):# 方法代码pass我们来定义一个最简单的猫类:
class Cat:def __init__(self, name, color):"""初始化方法,给猫对象设置名字和颜色"""self.name = name # 名字属性self.color = color # 颜色属性def meow(self):"""猫叫方法"""print(f"我是{self.color}的{self.name},喵~")这样我们就定义好了一个Cat类,现在我们根据这个类创建具体的猫对象:
# 创建两只不同的猫对象cat1 = Cat("橘橘", "橘黄色")cat2 = Cat("煤球", "黑色")# 调用它们的meow方法cat1.meow() # 输出:我是橘黄色的橘橘,喵~cat2.meow() # 输出:我是黑色的煤球,喵~完美!同一个模板创建出来的两个对象,各自有自己的属性,调用方法输出各自不同的内容,这就是类和对象最基本的用法。
关于self你需要知道
你可能注意到,每个方法第一个参数都是self,这是什么意思呢?
self代表的是当前对象本身,当对象调用方法的时候,Python会自动把对象自己传给self参数,所以你不用自己传在类的内部,要访问对象的属性或者调用对象的方法,都需要通过 self.属性名或者self.方法名()
记住这个规则就OK:定义方法的时候必须写self,调用方法的时候不用传self。
__init__方法是什么?
__init__方法是Python中的初始化方法,也叫构造方法,当你创建对象的时候,它会自动执行,用来给对象初始化属性,不用你手动调用。
两个下划线开头和结尾的方法,都是Python中的特殊方法,有特殊用途,我们后面会认识更多。
封装、继承、多态:面向对象三大特性
面向对象编程有三大核心特性:封装、继承、多态,我们一个个来讲:
1. 封装
封装就是说,把对象的属性和方法封装在一起,隐藏内部实现细节,只对外暴露必要的接口,简单理解就是:该公开的公开,该隐藏的隐藏,使用者不用知道内部怎么实现,只要会用接口就行。
举个例子,我们的手机,封装了所有内部电路,你只需要按开机键、点屏幕就行,不用知道里面芯片怎么工作,这就是封装。
在Python中,我们一般用单下划线开头表示私有属性(约定俗成,不建议外部直接访问):
class Person:def __init__(self, name, age):self.name = nameself._age = age # 私有属性,不建议外部直接访问# 提供公开方法获取和修改年龄def get_age(self):return self._agedef set_age(self, new_age):if 0 < new_age < 120: # 可以在这里做数据校验self._age = new_ageelse:print("年龄不合法!")封装的好处就是,我们可以在修改数据之前做校验,保证数据安全,内部实现改了不影响外部使用,这就是封装的意义。
2. 继承
继承就是说,一个类可以继承另一个类,继承之后,子类拥有父类所有的属性和方法,还可以添加自己特有的属性和方法,实现代码复用。
举个例子:我们先写一个Animal(动物)父类,里面有所有动物共有的属性和方法:
class Animal:def __init__(self, name):self.name = namedef eat(self):print(f"{self.name}会吃东西")然后我们写Dog(狗)类和Cat(猫)类,继承自Animal:
# Dog继承Animalclass Dog(Animal):def bark(self):# Dog自己特有的方法print(f"{self.name}会汪汪叫")# Cat继承Animalclass Cat(Animal):def meow(self):# Cat自己特有的方法print(f"{self.name}会喵喵叫")现在我们创建子类对象,看看能不能用父类的方法:
dog = Dog("旺财")dog.eat() # 输出:旺财会吃东西(继承自父类的方法)dog.bark() # 输出:旺财会汪汪叫(子类自己的方法)cat = Cat("橘橘")cat.eat() # 输出:橘橘会吃东西(继承自父类)cat.meow() # 输出:橘橘会喵喵叫(子类自己)完美!继承成功了,我们不用在每个子类里重新写eat方法,直接继承过来用就行,大大减少了重复代码,这就是继承的好处。
如果子类需要改写父类的方法,直接重写就行,比如:
class Dog(Animal):def eat(self):# 重写父类的eat方法print(f"{self.name}是狗狗,它吃肉")创建对象调用eat的时候,就会调用子类重写的版本了。
3. 多态
多态就是说,不同的对象调用同一个方法,会产生不同的结果,这就是多态。多态是继承带来的,我们来看例子:
class Animal:def speak(self):passclass Dog(Animal):def speak(self):print("汪汪汪")class Cat(Animal):def speak(self):print("喵喵喵")class Cow(Animal):def speak(self):print("哞哞哞")# 多态演示def animal_speak(animal): animal.speak()# 不同对象调用同一个方法,结果不同animal_speak(Dog()) # 汪汪汪animal_speak(Cat()) # 喵喵喵animal_speak(Cow()) # 哞哞哞看到了吗?同一个animal_speak函数,传入不同的动物对象,就会输出不同的结果,这就是多态。多态让我们的代码非常灵活,容易扩展,新增一个动物种类,只要继承Animal,实现speak方法就行,不用改原来的代码。
封装、继承、多态,就是面向对象的三大核心特性,理解了这三个,你就理解了面向对象的基本思想。
🎯 实战小案例:写一个学生管理类
我们来写一个简单的学生管理类,巩固一下今天学的知识点:
class StudentManager:def __init__(self):# 初始化一个空列表存储学生self.students = []def add_student(self, name, age, score):"""添加学生""" student = {"name": name,"age": age,"score": score }self.students.append(student)print(f"添加学生成功:{name}")def show_all(self):"""显示所有学生"""if not self.students:print("还没有任何学生")returnprint("当前所有学生信息:")for i, student in enumerate(self.students, 1):print(f"{i}. 姓名:{student['name']},年龄:{student['age']},分数:{student['score']}")def get_top_student(self):"""找出分数最高的学生"""if not self.students:return None top = max(self.students, key=lambda s: s["score"])print(f"分数最高的学生是:{top['name']},分数:{top['score']}")return top# 测试使用manager = StudentManager()manager.add_student("小明", 18, 90)manager.add_student("小红", 17, 95)manager.add_student("小刚", 18, 88)manager.show_all()manager.get_top_student()运行结果:
添加学生成功:小明添加学生成功:小红添加学生成功:小刚当前所有学生信息:1. 姓名:小明,年龄:18,分数:902. 姓名:小红,年龄:17,分数:953. 姓名:小刚,年龄:18,分数:88分数最高的学生是:小红,分数:95完美,一个简单的学生管理类就写好了,把数据(students列表)和操作数据的方法(add_student/show_all/get_top_student)封装在一起,逻辑清晰,使用方便,这就是面向对象的优势。
📝 今日小结
今天我们入门了Python面向对象编程,学习了类和对象,总结一下核心知识点:
基本概念:类是模板,对象是根据模板创建的具体实例 定义类:用 class关键字定义类,__init__方法初始化对象属性,第一个参数self代表当前对象三大特性: 封装:把属性和方法封装在一起,隐藏内部细节,暴露必要接口 继承:子类继承父类,复用父类代码,还可以扩展自己的功能 多态:不同对象调用同一个方法,产生不同结果,让代码更灵活 面向对象适合开发大型项目,代码更容易维护和扩展
面向对象是Python的核心编程思想,我们后面写项目都会用到它,一定要多练习理解。
🏋️ 今日作业
动手写代码才能真正理解,今天的作业:
1. 定义一个Rectangle(矩形)类,有长和宽两个属性,定义两个方法:计算面积和计算周长,然后创建对象测试
2. 定义一个Person类,有姓名、年龄属性,定义一个introduce方法,输出"我叫xx,今年xx岁"
3. 定义一个Animal父类,有move方法,然后定义Fish(鱼)子类继承Animal,重写move方法输出"鱼在水里游",定义Bird(鸟)子类,重写move方法输出"鸟在天上飞"
4. 拓展练习:用面向对象写一个简单的计算器类,实现加减乘除四个功能
好啦,今天我们入门了面向对象的类和对象,明天我们继续深入学习面向对象的进阶知识,比如魔法方法、属性和继承的进阶用法,敬请期待~
夜雨聆风