python-第27天:Python面向对象详解

30天入门Python(基础篇)------第27天:Python面向对象详解

📅 学习日期 :第27天 | ⏱️ 预计用时 :60分钟 | 📊 难度等级:⭐⭐⭐


🎯 学习目标

  • 理解面向对象编程的核心概念
  • 掌握类和对象的定义方法
  • 学会使用 __init__ 构造方法
  • 理解实例属性、实例方法、类属性、类方法的区别
  • 掌握 self 的作用和使用
  • 了解面向对象的三大特征:封装、继承、多态

一、什么是面向对象编程?

1.1 编程范式对比

面向过程编程:按照步骤一步步执行,关注"怎么做"。

python 复制代码
# 面向过程:步骤化
name = "小明"
age = 20
print(f"姓名: {name}, 年龄: {age}")

面向对象编程:将数据和操作封装成对象,关注"谁来做"。

python 复制代码
# 面向对象:对象化
student = Student("小明", 20)
student.introduce()

1.2 核心概念

概念 说明 生活类比
类(Class) 对象的模板/蓝图 汽车设计图
对象(Object) 类的具体实例 根据设计图制造的汽车
属性(Attribute) 对象的特征数据 汽车的颜色、品牌
方法(Method) 对象能执行的行为 汽车启动、加速

二、创建第一个类

2.1 基本语法

python 复制代码
class 类名:
    """类的文档字符串"""

    def __init__(self, 参数1, 参数2, ...):
        """构造方法"""
        self.属性1 = 参数1
        self.属性2 = 参数2

    def 方法名(self):
        """实例方法"""
        ...

2.2 实战示例:学生类

python 复制代码
class Student:
    """学生类"""

    def __init__(self, name, age, score):
        """初始化学生对象"""
        self.name = name      # 姓名
        self.age = age        # 年龄
        self.score = score    # 成绩

    def introduce(self):
        """自我介绍"""
        print(f"大家好,我是 {self.name},今年 {self.age} 岁。")

    def get_grade(self):
        """获取成绩等级"""
        if self.score >= 90:
            return "优秀"
        elif self.score >= 80:
            return "良好"
        elif self.score >= 60:
            return "及格"
        else:
            return "不及格"

# 创建对象
stu1 = Student("小明", 20, 95)
stu2 = Student("小红", 21, 78)

# 调用方法
stu1.introduce()  # 大家好,我是小明,今年20岁。
print(f"等级: {stu1.get_grade()}")  # 等级: 优秀

stu2.introduce()  # 大家好,我是小红,今年21岁。
print(f"等级: {stu2.get_grade()}")  # 等级: 及格

2.3 理解 self

self 是 Python 面向对象中的关键字参数,代表对象自身

python 复制代码
class Cat:
    def __init__(self, name):
        self.name = name   # self.name 是实例属性
                           # name 是局部参数

    def meow(self):
        # self 指向调用该方法的对象
        print(f"{self.name} 说: 喵~")

# 创建对象
cat = Cat("咪咪")
# 等价于: Cat.__init__(cat, "咪咪")

# 调用方法
cat.meow()
# 等价于: Cat.meow(cat)

self 的要点

  • self 不是关键字,只是一个约定(可以改成其他名字,但强烈建议不要改)
  • self 是方法的第一个参数,指向调用该方法的对象
  • 调用方法时,Python 自动传入 self,不需要手动传
  • __init__ 中,self.属性 = 值 就是创建实例属性

三、类的组成

3.1 构造方法 __init__

python 复制代码
class Person:
    def __init__(self, name, age=18):
        self.name = name
        self.age = age
        print(f"创建了 {self.name},年龄 {self.age}")

# 使用
p1 = Person("张三")       # age 使用默认值 18
p2 = Person("李四", 25)   # 指定 age

特点

  • __init__ 是特殊方法(魔术方法),在创建对象时自动调用
  • 可以有默认参数
  • 不能有返回值(隐式返回 None

3.2 实例方法

python 复制代码
class Calculator:
    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

calc = Calculator()
print(calc.add(3, 5))       # 8
print(calc.subtract(10, 4)) # 6

3.3 查看对象属性

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("小明", 20)

# 方式一:直接访问
print(p.name)   # 小明
print(p.age)    # 20

# 方式二:通过字典
print(p.__dict__)  # {'name': '小明', 'age': 20}

# 方式三:动态获取属性
print(getattr(p, "name"))     # 小明
print(getattr(p, "age"))      # 20
print(hasattr(p, "name"))     # True
print(hasattr(p, "email"))    # False

# 方式四:设置属性
setattr(p, "email", "test@example.com")
print(p.email)  # test@example.com

3.4 动态添加属性

python 复制代码
class Student:
    def __init__(self, name):
        self.name = name

stu = Student("小明")

# 动态添加属性(不推荐,应在 __init__ 中定义)
stu.age = 20
stu.email = "xiaoming@example.com"

print(stu.name)   # 小明
print(stu.age)    # 20
print(stu.email)  # xiaoming@example.com

四、属性的封装

4.1 私有属性

python 复制代码
class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner           # 公开属性
        self.__balance = balance     # 私有属性(双下划线前缀)

    def deposit(self, amount):
        """存款"""
        if amount > 0:
            self.__balance += amount
            print(f"存款 {amount},余额: {self.__balance}")
        else:
            print("金额必须为正数")

    def withdraw(self, amount):
        """取款"""
        if amount <= self.__balance:
            self.__balance -= amount
            print(f"取款 {amount},余额: {self.__balance}")
        else:
            print("余额不足")

    def get_balance(self):
        """查询余额(公开接口)"""
        return self.__balance

# 使用
account = BankAccount("张三", 1000)
account.deposit(500)    # 存款 500,余额: 1500
account.withdraw(200)   # 取款 200,余额: 1300

# 不能直接访问私有属性
# print(account.__balance)  # AttributeError

# 可以通过公开方法访问
print(f"当前余额: {account.get_balance()}")  # 1300

4.2 私有属性的本质

python 复制代码
class MyClass:
    def __init__(self):
        self.__secret = "hidden"

obj = MyClass()

# Python 实际上是将 __secret 改名为 _类名__secret
print(obj._MyClass__secret)  # hidden(可以访问,但不推荐)

命名约定

  • _name:受保护的属性(约定不要直接访问,但可以访问)
  • __name:私有属性(会被名称改写,外部难以直接访问)

五、@property 装饰器

5.1 属性访问控制

python 复制代码
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score  # 可以被任意修改

stu = Student("小明", 95)
stu.score = 150  # 不合理,但没有阻止

使用 @property 可以实现属性的读写控制:

python 复制代码
class Student:
    def __init__(self, name, score):
        self.name = name
        self._score = score  # 使用受保护的属性

    @property
    def score(self):
        """获取成绩(getter)"""
        return self._score

    @score.setter
    def score(self, value):
        """设置成绩(setter),带验证"""
        if not 0 <= value <= 100:
            raise ValueError("成绩必须在 0-100 之间")
        self._score = value

    @score.deleter
    def score(self):
        """删除成绩"""
        print(f"删除了 {self.name} 的成绩")
        del self._score

# 使用
stu = Student("小明", 95)
print(stu.score)      # 95(自动调用 getter)
stu.score = 88        # 自动调用 setter
print(stu.score)      # 88

stu.score = 150       # ValueError: 成绩必须在 0-100 之间

5.2 @property 的常见用法

python 复制代码
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    @property
    def area(self):
        """只读属性:计算面积"""
        return self.width * self.height

    @property
    def perimeter(self):
        """只读属性:计算周长"""
        return 2 * (self.width + self.height)

rect = Rectangle(5, 3)
print(f"面积: {rect.area}")       # 15
print(f"周长: {rect.perimeter}")  # 16

六、魔法方法(特殊方法)

6.1 __str____repr__

python 复制代码
class Student:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

    def __str__(self):
        """用户友好字符串,用于 print()"""
        return f"Student({self.name}, {self.age}岁, {self.score}分)"

    def __repr__(self):
        """开发者友好字符串,用于调试"""
        return f"Student(name='{self.name}', age={self.age}, score={self.score})"

stu = Student("小明", 20, 95)
print(stu)       # Student(小明, 20岁, 95分)
repr(stu)        # Student(name='小明', age=20, score=95)

区别

  • __str__:面向用户,print()str() 调用
  • __repr__:面向开发者,repr() 和交互式解释器调用
  • 如果只定义一个,优先定义 __repr__

6.2 常用魔法方法一览

python 复制代码
class MyClass:
    def __init__(self, value):
        self.value = value

    def __str__(self):          # str(obj), print(obj)
        return f"值为 {self.value}"

    def __repr__(self):         # repr(obj)
        return f"MyClass({self.value})"

    def __len__(self):          # len(obj)
        return self.value

    def __add__(self, other):   # obj1 + obj2
        return MyClass(self.value + other.value)

    def __eq__(self, other):    # obj1 == obj2
        return self.value == other.value

    def __lt__(self, other):    # obj1 < obj2
        return self.value < other.value

    def __getitem__(self, key): # obj[key]
        return self.value[key]

    def __len__(self):          # len(obj)
        return len(self.value)

    def __del__(self):          # del obj / 对象销毁时
        print(f"对象 {self} 被销毁")

6.3 自定义容器类

python 复制代码
class StudentList:
    """自定义学生列表"""
    def __init__(self):
        self._students = []

    def add(self, student):
        self._students.append(student)

    def __len__(self):
        return len(self._students)

    def __getitem__(self, index):
        return self._students[index]

    def __contains__(self, student):
        return student in self._students

    def __str__(self):
        return "\n".join(str(s) for s in self._students)

# 使用
students = StudentList()
students.add(Student("张三", 20, 95))
students.add(Student("李四", 21, 88))

print(len(students))        # 2
print(students[0])          # Student(张三, 20岁, 95分)
print(Student("张三", 20, 95) in students)  # True
print(students)             # 全部打印

七、类的继承与多态

7.1 继承基础(详细见第28天)

python 复制代码
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return f"{self.name} 说: 汪汪!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} 说: 喵喵!"

# 多态
animals = [Dog("旺财"), Cat("咪咪"), Dog("大黄")]
for animal in animals:
    print(animal.speak())

7.2 super() 函数

python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        return f"我叫 {self.name},今年 {self.age} 岁。"

class Teacher(Person):
    def __init__(self, name, age, subject):
        super().__init__(name, age)  # 调用父类构造
        self.subject = subject

    def introduce(self):
        base = super().introduce()  # 调用父类方法
        return f"{base} 我教 {self.subject}。"

teacher = Teacher("王老师", 35, "数学")
print(teacher.introduce())
# 我叫王老师,今年 35 岁。我教数学。

八、类方法、静态方法

8.1 实例方法、类方法、静态方法对比

python 复制代码
class MyClass:
    class_attr = "类属性"

    def __init__(self, value):
        self.value = value

    # 实例方法:需要 self,操作实例属性
    def instance_method(self):
        return f"实例方法: value = {self.value}"

    # 类方法:使用 @classmethod,需要 cls
    @classmethod
    def class_method(cls):
        return f"类方法: class_attr = {cls.class_attr}"

    # 静态方法:使用 @staticmethod,不需要 self 或 cls
    @staticmethod
    def static_method(x, y):
        return f"静态方法: {x} + {y} = {x + y}"

# 调用
obj = MyClass(42)
print(obj.instance_method())  # 实例方法: value = 42
print(obj.class_method())     # 类方法: class_attr = 类属性
print(obj.static_method(3, 5)) # 静态方法: 3 + 5 = 8

# 类方法可以直接通过类调用
print(MyClass.class_method())    # 类方法: class_attr = 类属性
print(MyClass.static_method(1, 2)) # 静态方法: 1 + 2 = 3

8.2 类方法的实用场景:工厂方法

python 复制代码
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def __str__(self):
        return f"{self.year}-{self.month:02d}-{self.day:02d}"

    @classmethod
    def from_string(cls, date_str):
        """从字符串创建日期对象(工厂方法)"""
        year, month, day = map(int, date_str.split("-"))
        return cls(year, month, day)

    @classmethod
    def today(cls):
        """获取今天的日期(工厂方法)"""
        from datetime import date
        today = date.today()
        return cls(today.year, today.month, today.day)

# 使用
d1 = Date(2026, 4, 28)
print(d1)  # 2026-04-28

d2 = Date.from_string("2026-01-01")
print(d2)  # 2026-01-01

d3 = Date.today()
print(d3)  # 2026-04-28

九、实战项目:图书管理系统

python 复制代码
class Book:
    """图书类"""
    def __init__(self, title, author, isbn):
        self.title = title
        self.author = author
        self.isbn = isbn
        self._is_borrowed = False

    @property
    def is_borrowed(self):
        return self._is_borrowed

    def borrow(self):
        if self._is_borrowed:
            print(f"《{self.title}》已被借出")
            return False
        self._is_borrowed = True
        print(f"借出《{self.title}》")
        return True

    def return_book(self):
        self._is_borrowed = False
        print(f"归还《{self.title}》")

    def __str__(self):
        status = "已借出" if self._is_borrowed else "可借阅"
        return f"《{self.title}》- {self.author} [{status}]"


class Library:
    """图书馆管理类"""
    def __init__(self, name):
        self.name = name
        self.books = []

    def add_book(self, book):
        self.books.append(book)
        print(f"添加图书: {book.title}")

    def remove_book(self, isbn):
        for book in self.books:
            if book.isbn == isbn:
                self.books.remove(book)
                print(f"删除图书: {book.title}")
                return
        print("未找到该图书")

    def search(self, keyword):
        results = [b for b in self.books if keyword in b.title or keyword in b.author]
        return results

    def list_books(self):
        if not self.books:
            print("图书馆暂无图书")
            return
        for book in self.books:
            print(f"  {book}")


# 使用
library = Library("中央图书馆")

# 添加图书
library.add_book(Book("Python编程", "张三", "978-1"))
library.add_book(Book("数据结构", "李四", "978-2"))
library.add_book(Book("算法导论", "王五", "978-3"))

print(f"\n📚 {library.name} 所有图书:")
library.list_books()

# 借书
print("\n借书操作:")
library.books[0].borrow()

# 搜索
print("\n搜索 'Python':")
for book in library.search("Python"):
    print(f"  {book}")

十、总结

概念 语法 说明
类定义 class 类名: 首字母大写的驼峰命名
构造方法 def __init__(self, ...): 创建对象时自动调用
实例方法 def method(self): 第一个参数必须是 self
类方法 @classmethod def method(cls): 第一个参数是 cls,通过类调用
静态方法 @staticmethod def method(): 不需要 selfcls
属性 self.attr = value 每个对象独立的属性
私有属性 self.__attr = value 名称改写,外部不易访问
属性控制 @property 控制属性的读写行为
字符串 __str__, __repr__ 自定义对象的字符串表示

十一、练习题

练习 1:银行账户类

创建一个 BankAccount 类,支持存款、取款、转账,余额不能为负。

练习 2:向量类

创建 Vector 类,支持向量加法、减法、点积运算,并且能计算向量长度。

练习 3:温度类

创建 Temperature 类,使用 @property 实现摄氏度、华氏度、开尔文之间的自动转换。

参考答案

练习 2 参考答案

python 复制代码
import math

class Vector:
    def __init__(self, *components):
        self.components = components

    def __add__(self, other):
        return Vector(*(a + b for a, b in zip(self.components, other.components)))

    def __sub__(self, other):
        return Vector(*(a - b for a, b in zip(self.components, other.components)))

    def dot(self, other):
        return sum(a * b for a, b in zip(self.components, other.components))

    def magnitude(self):
        return math.sqrt(sum(c ** 2 for c in self.components))

    def __str__(self):
        return f"Vector{self.components}"

v1 = Vector(1, 2, 3)
v2 = Vector(4, 5, 6)
print(v1 + v2)       # Vector(5, 7, 9)
print(v1.dot(v2))    # 32
print(v1.magnitude())  # 3.741...

🎉 恭喜你完成了第27天的学习!面向对象是 Python 编程的核心范式。

📌 下一天预告:第28天 ------ Python面向对象之继承与多继承

相关推荐
青 春 记 忆2 小时前
LeetCode 350. 两个数组的交集 II|Python 解法详解
python·算法·leetcode
迪康Defender2 小时前
公用电脑责任追溯难?迪康端点安全一体化管理系统用户模式详解
java·运维·开发语言·网络·其他·安全
16月6日-晴3 小时前
Java面向对象——接口
java·开发语言
wuyk5553 小时前
107.FreeRTOS 链表深度解析:从原理到面试满分答案
c语言·开发语言·数据结构·stm32·单片机·链表·面试
geovindu3 小时前
CSharp: Wordcloud
开发语言·后端·c#·.net·.netcore·词云
智购科技自动售卖机厂家3 小时前
2026自动售货机库存热力图分析:从设备分布到补货优先级的数据可视化实践~YH
大数据·python·信息可视化
Java小白笔记3 小时前
Java 实现 ZIP 压缩包生成方案
java·开发语言·网络·7-zip
Persistent的粽子!3 小时前
C++:类与对象(一)
开发语言·c++·经验分享·笔记
鹿鹿学长3 小时前
微软把语音转写打到 0.1 美元/小时:5 个月降价 72%,AI 音频进入地板价时代
python·自动化