大家好,我是Tbisnic。从今天从零教大家学习AI大模型,今天介绍Python中一个非常核心的概念——面向对象。一开始听到“对象”、“类”、“封装”这些词,感觉像在听天书。但学完之后我发现,面向对象其实就是让我们像“造物主”一样,用代码构建一个个“小世界”。下面我把今天的收获分享给大家,希望能帮助大家轻松入门!

一、两种编程思维:就像做菜 vs. 请厨师

编程解决问题有两种不同的思路:

1. 面向过程(步骤派)

  • 核心:关注“先做什么,后做什么”。

  • 例子:你要做一盘番茄炒蛋。面向过程就是:①洗番茄 → ②切番茄 → ③打蛋 → ④热油 → ⑤炒蛋 → ⑥加番茄 → ⑦调味 → ⑧出锅。每一步自己动手,顺序明确。

  • 缺点:如果换一道菜(比如红烧肉),所有步骤又要重新设计。

2. 面向对象(角色派)

  • 核心:关注“谁来做什么”。先设计好“角色”(对象),然后让角色去完成任务。

  • 例子:还是做菜。你请了一个厨师对象,他有“番茄”、“鸡蛋”、“锅铲”等属性,还有“切菜”、“炒菜”等方法。你只需要告诉厨师:“做一盘番茄炒蛋”,他自己就会调用内部的方法完成。下次你想吃红烧肉,还是这个厨师,换个指令就行。

  • Python的特点:两种风格都支持,但面向对象更适合大型项目,因为更接近我们认识世界的方式。

一句话总结:面向过程像写流水账,面向对象像拍电影(先有演员和剧本,再让他们演)。


二、类与对象:图纸和真车

1. 什么是类?

  • :是一类事物的模板图纸。它是抽象的,不能直接使用。

  • 比喻:手机厂商设计的一份“手机设计图”,上面写着:手机应该有屏幕、电池、摄像头(属性),可以打电话、玩游戏(方法)。但图纸本身不能拿来打电话。

2. 什么是对象?

  • 对象:根据类创建出来的具体个体。它是实实在在的,可以使用。

  • 比喻:工厂按照那份设计图造出了一部真正的“iPhone 15”,这部手机能开机、能拍照。这部真机就是对象

3. 核心关系

  • 先有类,后有对象。没有图纸,造不出任何真机。

  • 一个类可以创建无数个对象(比如小米10、小米11都是同一个类造出来的)。

4. 定义类与创建对象(代码演示)

# 定义类:一个简单的手机模板
class MobilePhone:
    def call(self):
        print("正在拨打电话...")

# 创建对象:造一部真机
my_phone = MobilePhone()   # 类名() 就是创建对象
my_phone.call()            # 输出:正在拨打电话...

三、self关键字:它就是“我自己”

  • 问题:同一个类创建了多个对象,对象调用方法时,方法怎么知道是哪个对象在叫我?

  • 答案self 就是那个“我自己”。谁调用方法,self 就代表谁。

  • 例子

    • 你和你朋友各有一部同型号手机。当你的手机响时,它知道“是你”在接听;你朋友的手机响时,它知道“是你朋友”在接听。

    • 在代码中,self 就是那个正在操作的对象本身。所以方法内部要用 self.属性 来操作当前对象的属性。

class Dog:
    def bark(self):
        print(f"{self} 在汪汪叫")   # self 就是调用该方法的对象

dog1 = Dog()
dog2 = Dog()
dog1.bark()   # 这里的 self 就是 dog1
dog2.bark()   # 这里的 self 就是 dog2

四、对象的属性:给对象贴上标签

1. 属性是什么?

  • 属性就是描述对象特征的变量。比如一个人的名字、年龄、身高。

2. 在类外部添加/获取属性(不推荐)

class Cat:
    pass

my_cat = Cat()
my_cat.name = "咪咪"      # 外部添加属性
print(my_cat.name)        # 输出:咪咪

避坑指南:千万不要在类外部随意添加属性!因为不同的猫对象可能有的有 name,有的没有,会导致程序混乱。正确的做法是在类内部统一初始化属性。

3. 在类内部推荐使用属性(通过 self

class Cat:
    def set_name(self, name):
        self.name = name   # 内部给当前对象的 name 赋值

    def show(self):
        print(f"我的名字是 {self.name}")

my_cat = Cat()
my_cat.set_name("咪咪")
my_cat.show()             # 输出:我的名字是 咪咪

五、魔法方法:Python中的“自动触发器”

魔法方法就是名字前后都有双下划线 __ 的方法,它们会在特定情况下自动被调用,不需要你手动写调用语句。

1. __init__:对象出生时的“第一声啼哭”

  • 触发时机:当你创建对象时(类名()),__init__ 会自动运行

  • 作用:用来给对象的属性赋初始值。就像婴儿一出生医生就会给他量身高体重。

class Book:
    def __init__(self, title):   # 参数 title 由外部传入
        self.title = title       # 把外部传入的书名保存为属性
        print(f"一本新书《{self.title}》诞生了!")

# 创建对象时自动调用 __init__
my_book = Book("三体")   # 输出:一本新书《三体》诞生了!

2. __str__:让打印对象变得“好看”

  • 触发时机:当你使用 print(对象) 时,自动调用。

  • 作用:返回一个字符串,描述这个对象的信息。如果不写,打印对象会输出 <__main__.Book object at 0x...>(一串内存地址,人类看不懂)。

class Book:
    def __init__(self, title):
        self.title = title

    def __str__(self):
        return f"《{self.title}》是一本很棒的书"

my_book = Book("三体")
print(my_book)   # 输出:《三体》是一本很棒的书

3. __del__:对象消亡前的“临终遗言”(了解即可)

  • 触发时机:对象被删除(del 对象)或者程序运行结束时自动调用。

  • 作用:做一些清理工作(比如关闭文件、断开网络连接)。一般情况下不需要特意写它。

class Animal:
    def __del__(self):
        print("对象被销毁了,再见!")

dog = Animal()
del dog   # 输出:对象被销毁了,再见!

六、【原创案例】自动售货机 —— 综合运用面向对象

为了把上面所有知识串起来,我设计了一个自动售货机的案例,不使用原笔记中的减肥或烤地瓜。

需求分析

  • 售货机里有饮料,每瓶价格5元。

  • 用户可以投币、购买饮料、查看剩余饮料数量。

  • 购买时如果余额不足或库存不足,给出提示。

  • 打印售货机信息时,能清晰看到库存和当前收入。

步骤

  1. 定义 VendingMachine 类。

  2. __init__ 初始化属性:beverage_count(饮料数量)、balance(当前投币金额)、total_income(总收入)。

  3. 提供 insert_coin(money) 方法:投币,累加 balance

  4. 提供 buy() 方法:判断余额是否≥5且库存>0,是则减少库存、扣除5元余额、增加总收入,否则提示失败。

  5. 提供 refill(count) 方法:补充饮料。

  6. __str__ 方法:返回售货机状态。

代码实现

class VendingMachine:
    def __init__(self, initial_count):
        """初始化售货机:饮料数量、当前投币金额、总收入"""
        self.beverage_count = initial_count
        self.balance = 0
        self.total_income = 0

    def insert_coin(self, money):
        """投币,累加到 balance"""
        if money <= 0:
            print("请投入正数金额")
            return
        self.balance += money
        print(f"投币成功,当前余额:{self.balance} 元")

    def buy(self):
        """购买饮料:需要余额>=5 且 库存>0"""
        if self.beverage_count <= 0:
            print("抱歉,饮料已售罄")
            return
        if self.balance < 5:
            print(f"余额不足,还需要 {5 - self.balance} 元")
            return
        # 成功购买
        self.beverage_count -= 1
        self.balance -= 5
        self.total_income += 5
        print("购买成功!请取走饮料。")
        print(f"剩余余额:{self.balance} 元,剩余饮料:{self.beverage_count} 瓶")

    def refill(self, count):
        """补充饮料"""
        if count <= 0:
            print("补充数量必须大于0")
            return
        self.beverage_count += count
        print(f"补充 {count} 瓶饮料,当前库存:{self.beverage_count} 瓶")

    def __str__(self):
        return f"=== 售货机状态 ===\n饮料库存:{self.beverage_count} 瓶\n当前投币余额:{self.balance} 元\n总收入:{self.total_income} 元"

# 测试
if __name__ == "__main__":
    vm = VendingMachine(3)          # 初始3瓶饮料
    print(vm)

    vm.insert_coin(10)              # 投10元
    vm.buy()                        # 购买一次
    vm.buy()                        # 再买一次(余额还剩5元,可以买第二瓶)
    vm.buy()                        # 再买(余额0,不够)
    vm.refill(2)                    # 补货2瓶
    vm.insert_coin(5)
    vm.buy()                        # 成功购买
    print(vm)

运行效果预览

=== 售货机状态 ===
饮料库存:3 瓶
当前投币余额:0 元
总收入:0 元
投币成功,当前余额:10 元
购买成功!请取走饮料。
剩余余额:5 元,剩余饮料:2 瓶
购买成功!请取走饮料。
剩余余额:0 元,剩余饮料:1 瓶
余额不足,还需要 5 元
补充 2 瓶饮料,当前库存:3 瓶
投币成功,当前余额:5 元
购买成功!请取走饮料。
剩余余额:0 元,剩余饮料:2 瓶
=== 售货机状态 ===
饮料库存:2 瓶
当前投币余额:0 元
总收入:15 元

七、面向对象三大特性(概述)

  1. 封装:把数据和操作数据的方法打包在一个类内部,并隐藏内部细节(比如售货机不需要告诉你它怎么找零,你只管投币和按按钮)。

  2. 继承:子类可以自动拥有父类的所有属性和方法。比如“咖啡售货机”继承自“售货机”,再增加煮咖啡的功能。

  3. 多态:同一个方法,不同对象调用产生不同结果。比如“猫”和“狗”都有“叫”的方法,但猫叫“喵”,狗叫“汪”。

今天重点学习封装,尤其是其中的私有属性和方法。


八、封装与私有权限:保护你的“核心秘密”

1. 为什么需要私有?

  • 现实世界:银行卡密码不能随便让别人看,只能由银行系统内部修改。

  • 程序世界:有些属性或方法不希望被类外部直接访问或修改,以免造成数据错乱。

2. 如何定义私有属性和方法?

  • 在属性名或方法名前加 双下划线 __

class BankAccount:
    def __init__(self, password):
        self.__password = password   # 私有属性,外部无法直接访问

    def __check_password(self):      # 私有方法,外部无法直接调用
        print("验证密码...")

    def withdraw(self, money):
        # 内部可以自由使用私有属性和方法
        self.__check_password()
        print(f"取出 {money} 元")

3. 访问规则

  • 类内部:可以随便用 self.__私有属性 和 self.__私有方法()

  • 类外部:直接 对象.__私有属性 会报错 AttributeError

  • 子类:子类也无法继承父类的私有属性和方法。

4. 如果外部非要访问怎么办?

提供一个公开的“接口方法”(getter / setter),在内部控制访问逻辑。

class BankAccount:
    def __init__(self, password):
        self.__password = password

    def get_password(self):     # 公开的获取方法
        return "密码不可见"

    def set_password(self, new_pwd):
        if len(new_pwd) == 6:   # 可以加校验规则
            self.__password = new_pwd
            print("密码修改成功")
        else:
            print("密码必须是6位")

acc = BankAccount("123456")
print(acc.get_password())       # 输出:密码不可见
acc.set_password("abc")         # 输出:密码必须是6位
acc.set_password("654321")      # 输出:密码修改成功

这样既保护了数据,又允许外界通过安全的方式操作。


九、总结 

今天我们介绍了:

  • 面向对象和面向过程的区别

  • 类和对象(图纸与真车)

  • self 指向当前对象

  • 属性添加(最好在 __init__ 中统一初始化)

  • 魔法方法 __init____str____del__

  • 综合案例:自动售货机

  • 面向对象三大特性

  • 封装与私有属性和方法

给大家的一句话:

面向对象并不神秘,它就是我们看待世界的自然方式。每当你看到一个东西(手机、猫、售货机),都可以想想:它有什么属性?它能做什么事情?然后试着用类把它描述出来。

第一篇AI大模型学习博客就写到这里,明天继续学继承和多态。加油,我们一起进步

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐