Python面向对象编程:类与对象基础

Python面向对象编程:类与对象基础

面向对象编程(OOP)是编程的重要范式,Python是一门完全面向对象的语言。本篇将学习类与对象的基本概念、定义和使用。

一、什么是面向对象?

1. 面向过程 vs 面向对象

  • 面向过程:以「动作」为中心,关注「怎么做」,用函数组织代码
  • 面向对象:以「事物」为中心,关注「谁来做」,用类和对象组织代码

生活类比

  • 面向过程:把大象装进冰箱 → 开门 → 装大象 → 关门(关注步骤)
  • 面向对象:冰箱有开门/关门方法,大象有被装的属性(关注对象)

2. 类与对象的关系

  • 类(Class):是模板/蓝图,描述一类事物的共同特征和行为
  • 对象(Object):是类的具体实例,是真实存在的个体

比如:

  • 「人类」是一个类,「张三」是人类的一个对象
  • 「汽车」是一个类,「你家那辆车」是汽车的一个对象

二、定义类和创建对象

1. 基本语法

python 复制代码
class 类名:
    """类文档字符串"""
    
    def __init__(self, 参数列表):
        """初始化方法,创建对象时自动调用"""
        self.属性名 = 参数
    
    def 方法名(self, 参数列表):
        """实例方法"""
        方法体

2. 第一个类:Person

python 复制代码
class Person:
    """人类"""
    
    def __init__(self, name, age):
        """初始化方法"""
        self.name = name  # 实例属性
        self.age = age
    
    def say_hello(self):
        """打招呼方法"""
        print(f"你好,我叫{self.name},今年{self.age}岁")
    
    def have_birthday(self):
        """过生日,年龄+1"""
        self.age += 1
        print(f"生日快乐!{self.name}现在{self.age}岁了")

# 创建对象(实例化)
p1 = Person("小明", 18)
p2 = Person("小红", 17)

# 调用方法
p1.say_hello()  # 你好,我叫小明,今年18岁
p2.say_hello()  # 你好,我叫小红,今年17岁

p1.have_birthday()  # 生日快乐!小明现在19岁了

# 访问属性
print(p1.name)  # 小明
print(p1.age)   # 19

3. self是什么?

self 代表当前对象本身,类似于其他语言中的 this

  • 定义方法时,第一个参数必须是self(约定俗成,也可以叫别的名字,但不建议)
  • 调用方法时,不需要手动传self,Python会自动传入
  • 通过self可以访问对象的属性和其他方法
python 复制代码
class Demo:
    def show(self):
        print(f"self的id: {id(self)}")

d = Demo()
d.show()          # self的id: 140...
print(f"d的id: {id(d)}")  # d的id: 140...(和self相同)

三、属性详解

1. 实例属性 vs 类属性

python 复制代码
class Dog:
    # 类属性:所有实例共享
    species = "犬科动物"
    count = 0  # 计数器
    
    def __init__(self, name, age):
        # 实例属性:每个实例独有
        self.name = name
        self.age = age
        Dog.count += 1  # 创建一个实例,计数器+1

# 创建实例
d1 = Dog("旺财", 3)
d2 = Dog("大黄", 5)

# 实例属性(每个对象不同)
print(d1.name)  # 旺财
print(d2.name)  # 大黄

# 类属性(所有对象共享)
print(d1.species)  # 犬科动物
print(d2.species)  # 犬科动物
print(Dog.count)   # 2(创建了2个实例)

# 修改类属性(通过类名修改,影响所有实例)
Dog.species = "哺乳动物"
print(d1.species)  # 哺乳动物

# 通过实例修改类属性(实际上是创建了同名实例属性,不影响其他实例)
d1.species = "小狗狗"
print(d1.species)  # 小狗狗(实例属性)
print(d2.species)  # 哺乳动物(还是类属性)

2. 属性访问控制

Python没有真正的私有属性,但有约定:

python 复制代码
class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner        # 公开属性
        self._balance = balance   # 约定为"内部使用"(单下划线)
        self.__password = "1234"  # 名称修饰,外部不能直接访问(双下划线)
    
    def get_balance(self):
        """获取余额(通过方法访问私有属性)"""
        return self._balance
    
    def deposit(self, amount):
        """存款"""
        if amount > 0:
            self._balance += amount
            print(f"存款{amount}成功,余额{self._balance}")
        else:
            print("存款金额必须大于0")

account = BankAccount("小明", 1000)
print(account.get_balance())  # 1000
account.deposit(500)          # 存款500成功,余额1500

# print(account.__password)  # 报错,不能直接访问
print(account._BankAccount__password)  # 可以通过这种方式访问(不推荐)

⚠️ Python的「私有」是约定大于强制,双下划线只是名称修饰,不是真正的访问控制。

3. @property装饰器

用property可以把方法变成属性访问,实现getter/setter。

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 0 <= value <= 100:
            self._score = value
        else:
            raise ValueError("分数必须在0-100之间")
    
    @property
    def grade(self):
        """只读属性(只有getter,没有setter)"""
        if self._score >= 90:
            return "A"
        elif self._score >= 80:
            return "B"
        elif self._score >= 60:
            return "C"
        else:
            return "D"

s = Student("小明", 85)
print(s.score)  # 85(像访问属性一样调用方法)
print(s.grade)  # B

s.score = 95    # 通过setter修改
print(s.score)  # 95
print(s.grade)  # A

# s.score = 120  # 会抛出ValueError

四、方法详解

1. 实例方法

最常见的方法,第一个参数是self,可以访问实例属性和类属性。

python 复制代码
class Example:
    def instance_method(self):
        print("这是实例方法", self)

2. 类方法

@classmethod 装饰,第一个参数是cls(代表类本身)。

python 复制代码
class Person:
    total = 0
    
    def __init__(self, name):
        self.name = name
        Person.total += 1
    
    @classmethod
    def get_total(cls):
        """类方法:访问类属性"""
        return cls.total
    
    @classmethod
    def from_string(cls, info_str):
        """类方法:作为备用构造函数"""
        name = info_str.split("-")[0]
        return cls(name)  # cls相当于Person

print(Person.get_total())  # 0
p1 = Person("小明")
print(Person.get_total())  # 1

# 用类方法创建对象
p2 = Person.from_string("小红-18")
print(p2.name)  # 小红

3. 静态方法

@staticmethod 装饰,不需要self或cls参数,就是普通函数放在类里。

python 复制代码
class MathUtils:
    @staticmethod
    def is_even(n):
        """判断是否为偶数"""
        return n % 2 == 0
    
    @staticmethod
    def max_of(a, b):
        return a if a > b else b

# 不需要创建对象,直接通过类调用
print(MathUtils.is_even(4))   # True
print(MathUtils.max_of(3, 5)) # 5

4. 三种方法对比

方法类型 装饰器 第一个参数 能访问实例属性 能访问类属性
实例方法 self
类方法 @classmethod cls
静态方法 @staticmethod

五、实战:银行账户类

python 复制代码
class BankAccount:
    """银行账户类"""
    
    # 类属性
    bank_name = "Python银行"
    total_accounts = 0
    
    def __init__(self, owner, balance=0):
        """初始化账户"""
        self.owner = owner
        self.__balance = balance  # 私有属性
        self.transaction_history = []  # 交易记录
        BankAccount.total_accounts += 1
    
    @property
    def balance(self):
        """只读余额属性"""
        return self.__balance
    
    def deposit(self, amount):
        """存款"""
        if amount <= 0:
            print("存款金额必须大于0")
            return False
        self.__balance += amount
        self.transaction_history.append(("存款", amount))
        print(f"存款成功:+{amount}元,当前余额:{self.__balance}元")
        return True
    
    def withdraw(self, amount):
        """取款"""
        if amount <= 0:
            print("取款金额必须大于0")
            return False
        if amount > self.__balance:
            print("余额不足")
            return False
        self.__balance -= amount
        self.transaction_history.append(("取款", amount))
        print(f"取款成功:-{amount}元,当前余额:{self.__balance}元")
        return True
    
    def transfer(self, target, amount):
        """转账到另一个账户"""
        if self.withdraw(amount):
            target.deposit(amount)
            print(f"转账成功:从{self.owner}转到{target.owner} {amount}元")
            return True
        return False
    
    def show_history(self):
        """显示交易记录"""
        print(f"\n{self.owner}的交易记录:")
        for op, amount in self.transaction_history:
            print(f"  {op}: {amount}元")
        print(f"  最终余额: {self.__balance}元")
    
    @classmethod
    def get_total_accounts(cls):
        """获取总账户数"""
        return cls.total_accounts

# 使用示例
print(f"欢迎使用{BankAccount.bank_name}")
print(f"当前总账户数:{BankAccount.get_total_accounts()}")

# 创建账户
acc1 = BankAccount("小明", 1000)
acc2 = BankAccount("小红", 500)

# 操作
acc1.deposit(500)
acc1.withdraw(200)
acc1.transfer(acc2, 300)

# 查看记录
acc1.show_history()
acc2.show_history()

print(f"\n当前总账户数:{BankAccount.get_total_accounts()}")

六、常见坑点

  1. __init__没有return:初始化方法不能返回值,只能返回None

  2. 忘记self:方法定义时第一个参数必须是self,否则调用时报错

  3. 类属性和实例属性混淆:修改类属性要用类名,通过实例修改会创建同名实例属性

  4. 可变对象作为类属性 :所有实例共享同一个列表/字典,修改会互相影响

    python 复制代码
    class Demo:
        items = []  # 危险!所有实例共享
    
    d1 = Demo()
    d2 = Demo()
    d1.items.append(1)
    print(d2.items)  # [1](被影响了!)

七、课后练习

  1. 定义一个Circle类,包含半径属性,实现计算面积和周长的方法
  2. 定义一个Book类,包含书名、作者、价格属性,用@property实现价格不能为负数
  3. 定义一个Car类,包含品牌、速度属性,实现加速、减速方法(速度不能为负)
  4. 定义一个Student类,用类方法实现从字符串创建学生对象(如"张三,18,90")

八、小结

本篇学习了面向对象的基本概念、类的定义、实例属性与类属性、三种方法类型(实例方法/类方法/静态方法)以及@property装饰器。面向对象是编程的重要思维方式,下一篇将学习继承、多态等进阶特性。

📌 下一篇预告:《Python面向对象进阶:继承、多态与魔术方法》


本专栏持续更新中,欢迎点赞、收藏、关注三连支持!🐍

相关推荐
RD_daoyi16 分钟前
谷歌改写了76%的标题:超60字符的,95%会被谷歌自己重写
大数据·服务器·开发语言·前端·搜索引擎·html
weixin_3077791317 分钟前
AI生成代码的隐患与治理:人工审查流程及提示词驱动的修复策略
开发语言·人工智能·算法
muddjsv18 分钟前
Python 神经网络入门:用 scikit-learn 完成 MLP 分类与回归
python·神经网络·scikit-learn
Java后端的Ai之路21 分钟前
09、Python组合模式
开发语言·人工智能·python·docker·组合模式
Escalating_xu26 分钟前
【C++入门基础(上)】从发展历程、学习路线到命名空间与输入输出
开发语言·c++
Tenifs27 分钟前
Python Loguru 使用指南
python·loguru
jimy129 分钟前
C++ 中的rValue的判断---是否能“隐式移动”
开发语言·c++
青 春 记 忆30 分钟前
零基础入门python36:用 Django Session 实现购物车
python·django·后端开发