Skip to content

26|类与对象

程序需要描述具有相同特征和行为的一组事物。学生有姓名、年龄、成绩,能学习、能考试;商品有名称、价格、库存,能上架、能售出。类(class)是这类事物的抽象定义,对象(object)是类的具体实例。

Python 支持面向对象编程,但不像 Java 那样强制所有代码都放在类里。类在需要封装数据和行为时使用,简单脚本可以用函数和模块解决。

一、定义类

python
class Student:
    """学生类。"""

    def __init__(self, name, age):
        self.name = name
        self.age = age

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

class 关键字定义类。__init__ 是构造方法,创建对象时自动调用。self 代表对象本身,必须通过 self 访问对象的属性和方法。

创建对象:

python
alice = Student("Alice", 20)
print(alice.name)           # Alice
print(alice.introduce())    # 我是Alice,今年20岁

二、属性和方法

类中定义的变量叫属性,函数叫方法。

python
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

rect = Rectangle(5, 3)
print(rect.area())        # 15
print(rect.perimeter())   # 16

三、self 的本质

self 是方法的第一个参数,代表调用该方法的对象。Python 在调用方法时自动传入这个参数:

python
rect.area()      # 等价于 Rectangle.area(rect)

方法定义时必须有 self,调用时不需要传。

四、类属性 vs 实例属性

实例属性绑定到具体对象,每个对象有自己的一份:

python
alice = Student("Alice", 20)
bob = Student("Bob", 21)

alice.age = 21       # 只修改 alice,不影响 bob

类属性绑定到类本身,所有对象共享:

python
class Student:
    school = "第一中学"   # 类属性

    def __init__(self, name, age):
        self.name = name   # 实例属性
        self.age = age

alice = Student("Alice", 20)
bob = Student("Bob", 21)

print(alice.school)   # 第一中学
print(bob.school)     # 第一中学

Student.school = "第二中学"
print(alice.school)   # 第二中学,所有实例都变了

通过对象修改类属性会创建实例属性,不影响其他对象:

python
alice.school = "实验中学"   # 给 alice 创建实例属性 school
print(alice.school)         # 实验中学
print(bob.school)           # 第二中学,没变

五、动态添加属性

Python 允许给对象动态添加属性:

python
alice = Student("Alice", 20)
alice.score = 95     # 动态添加属性
print(alice.score)   # 95

这个特性很灵活,但也容易出错——拼写错误不会报错,只是创建了一个新属性:

python
print(alice.scroe)   # AttributeError,拼写错误

六、私有属性

Python 没有真正的私有属性。以双下划线开头的属性会被改名(name mangling),不容易从外部直接访问:

python
class BankAccount:
    def __init__(self, balance):
        self.__balance = balance   # 伪私有属性

    def get_balance(self):
        return self.__balance

account = BankAccount(1000)
print(account.get_balance())   # 1000
print(account.__balance)       # AttributeError
print(account._BankAccount__balance)   # 1000,通过改名后的名称仍可访问

单下划线开头的属性(如 _balance)是约定俗成的"内部使用",不会阻止访问,只是提示"不要直接碰"。

记忆锚点class 定义类,__init__ 构造方法;self 代表对象本身,定义时写、调用时不传;实例属性每个对象独立,类属性所有对象共享;动态添加属性灵活但容易拼写出错;双下划线属性被改名,单下划线是约定内部使用。