第52集:类与对象基础

学习目标

  • 掌握如何定义类
  • 学会创建和使用对象
  • 理解类属性和实例属性
  • 掌握类方法、实例方法和静态方法
  • 了解对象的生命周期
  • 掌握对象的内存管理

一、定义类

1.1 类的定义语法

class ClassName:
    """类文档字符串"""
    # 类体
    # 属性
    # 方法
    pass

1.2 基本示例

# 定义一个简单的类
class Person:
    """人类"""
    
    # 类属性(所有对象共享)
    species = "人类"
    
    # 实例方法
    def say_hello(self):
        print("你好!")

1.3 命名规范

  • 类名:使用大驼峰命名法(PascalCase)

    • 例如:PersonStudentBankAccount
  • 方法名:使用小写加下划线(snake_case)

    • 例如:say_helloget_nameset_age
  • 属性名:使用小写加下划线(snake_case)

    • 例如:nameageaddress

二、创建对象

2.1 创建对象的语法

# 对象创建的语法
对象名 = 类名()

2.2 创建对象示例

class Person:
    species = "人类"
    
    def say_hello(self):
        print("你好!")

# 创建对象
person1 = Person()
person2 = Person()

# 使用对象
person1.say_hello()  # 输出:你好!
person2.say_hello()  # 输出:你好!

2.3 对象的独立性

class Counter:
    count = 0  # 类属性
    
    def increment(self):
        self.count += 1  # 创建实例属性

# 创建多个对象
c1 = Counter()
c2 = Counter()

# 每个对象的属性是独立的
c1.increment()
c1.increment()
c2.increment()

print(f"c1.count: {c1.count}")  # 输出:2
print(f"c2.count: {c2.count}")  # 输出:1

三、类属性 vs 实例属性

3.1 类属性

定义: 定义在类中、方法外的属性,所有对象共享。

特点:

  • 所有对象共享同一个值
  • 通过类名或对象名访问
  • 修改类属性会影响所有对象

示例:

class Dog:
    species = "犬科动物"  # 类属性
    
    def __init__(self, name):
        self.name = name  # 实例属性

# 访问类属性
print(Dog.species)  # 输出:犬科动物

# 通过对象访问
dog1 = Dog("小白")
dog2 = Dog("小黑")
print(dog1.species)  # 输出:犬科动物
print(dog2.species)  # 输出:犬科动物

# 修改类属性
Dog.species = "狗"
print(dog1.species)  # 输出:狗
print(dog2.species)  # 输出:狗

3.2 实例属性

定义: 定义在__init__方法中,通过self设置的属性,每个对象独立拥有。

特点:

  • 每个对象有自己独立的值
  • 只能通过对象名访问
  • 修改实例属性不影响其他对象

示例:

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

# 创建对象
s1 = Student("张三", 18)
s2 = Student("李四", 19)

# 每个对象的属性是独立的
print(f"s1: {s1.name}, {s1.age}")  # 输出:s1: 张三, 18
print(f"s2: {s2.name}, {s2.age}")  # 输出:s2: 李四, 19

# 修改实例属性
s1.name = "王五"
s1.age = 20

print(f"s1: {s1.name}, {s1.age}")  # 输出:s1: 王五, 20
print(f"s2: {s2.name}, {s2.age}")  # 输出:s2: 李四, 19

3.3 属性查找顺序

当访问一个属性时,Python的查找顺序:

实例属性 -> 类属性 -> 报错

示例:

class MyClass:
    class_attr = "类属性"
    
    def __init__(self):
        self.instance_attr = "实例属性"

obj = MyClass()

# 优先访问实例属性
print(obj.instance_attr)  # 输出:实例属性

# 访问类属性
print(obj.class_attr)     # 输出:类属性

# 修改(实际上是创建实例属性)
obj.class_attr = "修改后的实例属性"
print(obj.class_attr)     # 输出:修改后的实例属性
print(MyClass.class_attr) # 输出:类属性(未改变)

四、实例方法

4.1 定义实例方法

class ClassName:
    def method_name(self, 参数1, 参数2, ...):
        # 方法体
        pass

关键点:

  • 方法的第一个参数必须是self
  • self代表当前对象实例
  • 通过self可以访问对象的属性和方法

4.2 self的作用

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def introduce(self):
        # 通过self访问属性
        print(f"我叫{self.name},今年{self.age}岁")
    
    def greet(self, other):
        # self代表当前对象,other代表其他对象
        print(f"{self.name}向{other.name}打招呼")

# 创建对象
p1 = Person("张三", 18)
p2 = Person("李四", 20)

p1.introduce()  # 输出:我叫张三,今年18岁
p1.greet(p2)    # 输出:张三向李四打招呼

4.3 方法的类型

4.3.1 实例方法

class MyClass:
    def instance_method(self):
        print("这是实例方法")
        print(f"self的值: {self}")

4.3.2 类方法(使用@classmethod装饰器)

class MyClass:
    class_attr = "类属性"
    
    @classmethod
    def class_method(cls):
        print("这是类方法")
        print(f"cls的值: {cls}")
        print(f"访问类属性: {cls.class_attr}")

# 调用类方法
MyClass.class_method()

特点:

  • 第一个参数是cls,代表类本身
  • 可以访问类属性和类方法
  • 通过类名或对象名调用

4.3.3 静态方法(使用@staticmethod装饰器)

class MyClass:
    @staticmethod
    def static_method():
        print("这是静态方法")
        # 不能访问self或cls

# 调用静态方法
MyClass.static_method()

特点:

  • 不需要特殊的第一个参数
  • 不能访问实例属性或类属性
  • 通常用于工具函数

4.4 三种方法的对比

类型 第一个参数 调用方式 可访问 用途
实例方法 self 对象名 实例属性和方法 操作对象数据
类方法 cls 类名或对象名 类属性和方法 操作类数据
静态方法 类名或对象名 工具函数

综合示例:

class MathUtil:
    pi = 3.14159  # 类属性
    
    # 实例方法
    def __init__(self, value):
        self.value = value
    
    def multiply(self, other):
        return self.value * other
    
    # 类方法
    @classmethod
    def get_pi(cls):
        return cls.pi
    
    # 静态方法
    @staticmethod
    def add(a, b):
        return a + b

# 使用
util = MathUtil(5)
print(util.multiply(3))   # 输出:15(实例方法)
print(MathUtil.get_pi())  # 输出:3.14159(类方法)
print(MathUtil.add(2, 3)) # 输出:5(静态方法)

五、对象的生命周期

5.1 对象的创建过程

1. 分配内存空间
2. 调用__init__方法初始化
3. 返回对象引用

示例:

class Demo:
    def __init__(self, name):
        print("对象正在创建...")
        self.name = name
        print("对象创建完成!")

obj = Demo("测试对象")
# 输出:
# 对象正在创建...
# 对象创建完成!

5.2 对象的使用

class Person:
    def __init__(self, name):
        self.name = name
    
    def work(self):
        print(f"{self.name}在工作")

# 创建对象
p = Person("张三")

# 使用对象
p.work()  # 调用方法
print(p.name)  # 访问属性

5.3 对象的销毁

class Demo:
    def __del__(self):
        print("对象被销毁了")

def create_demo():
    d = Demo()
    print("函数结束")

create_demo()
# 输出:
# 函数结束
# 对象被销毁了

六、动态添加属性和方法

6.1 动态添加属性

class Person:
    def __init__(self, name):
        self.name = name

p = Person("张三")

# 动态添加属性
p.age = 18
p.city = "北京"

print(p.name)  # 输出:张三
print(p.age)   # 输出:18
print(p.city)  # 输出:北京

6.2 动态添加方法

class Person:
    def __init__(self, name):
        self.name = name

def new_method(self):
    print(f"{self.name}的新方法")

# 动态添加方法
Person.new_func = new_method

p = Person("张三")
p.new_func()  # 输出:张三的新方法

6.3 删除属性

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

p = Person("张三", 18)

# 删除属性
del p.age

print(p.name)  # 输出:张三
print(p.age)   # 报错:AttributeError

七、实例:学生类

7.1 完整示例

class Student:
    """学生类"""
    
    # 类属性
    school = "Python学院"
    total_students = 0
    
    def __init__(self, name, age, grade):
        """初始化学生"""
        self.name = name
        self.age = age
        self.grade = grade
        Student.total_students += 1
    
    def introduce(self):
        """自我介绍"""
        print(f"大家好,我是{self.name},今年{self.age}岁,{self.grade}年级")
    
    def study(self, subject):
        """学习"""
        print(f"{self.name}正在学习{subject}")
    
    @classmethod
    def get_total_students(cls):
        """获取学生总数"""
        return cls.total_students
    
    @classmethod
    def change_school(cls, new_school):
        """更换学校"""
        cls.school = new_school
    
    @staticmethod
    def calculate_average(scores):
        """计算平均分"""
        return sum(scores) / len(scores)

# 使用示例
s1 = Student("张三", 18, "大一")
s2 = Student("李四", 19, "大二")
s3 = Student("王五", 20, "大三")

s1.introduce()
s2.study("Python编程")

print(f"学生总数:{Student.get_total_students()}")
print(f"学校:{s1.school}")

average = Student.calculate_average([85, 90, 78, 92, 88])
print(f"平均分:{average}")

八、常见错误与注意事项

8.1 常见错误

  1. 忘记self参数:
class Person:
    def say_hello():  # 错误:缺少self
        print("你好!")
  1. 类方法错误使用:
class MyClass:
    def method(cls):  # 错误:应该使用@classmethod装饰器
        pass
  1. 混淆类属性和实例属性:
class Counter:
    count = 0  # 类属性
    
    def increment(self):
        count += 1  # 错误:应该使用self.count

8.2 注意事项

  1. 类名使用大驼峰命名
  2. 实例方法必须有self参数
  3. 类方法使用@classmethod装饰器
  4. 静态方法使用@staticmethod装饰器
  5. 避免动态修改类属性,以免影响其他对象

九、课后练习

练习题

  1. 编程题

    • 定义一个Circle类,包含半径属性和计算面积、周长的方法
    • 定义一个Rectangle类,包含长和宽属性和计算面积、周长的方法
    • 添加类方法和静态方法
  2. 编程题

    • 定义一个Book类,包含书名、作者、价格属性
    • 添加实例方法:显示书籍信息、打折
    • 添加类方法:统计创建的书籍数量
    • 添加静态方法:判断价格是否合理
  3. 编程题

    • 定义一个BankAccount
    • 包含账号、余额属性
    • 添加存款、取款、查询余额方法
    • 使用类属性记录账户总数
  4. 分析题

    • 分析以下代码的输出结果
    class A:
        x = 1
        
        def __init__(self):
            self.x = 2
    
    a = A()
    print(A.x)
    print(a.x)

十、本集总结

核心知识点回顾

  1. 类定义:使用class关键字定义类
  2. 对象创建:使用类名()创建对象
  3. 类属性:所有对象共享,通过类名或对象名访问
  4. 实例属性:每个对象独立,通过对象名访问
  5. 实例方法:第一个参数是self,操作对象数据
  6. 类方法:使用@classmethod,操作类数据
  7. 静态方法:使用@staticmethod,不访问对象或类数据
  8. 对象生命周期:创建、使用、销毁

下集预告

下一集我们将学习**构造方法__init__**,深入了解如何正确初始化对象。


学习建议: 多编写不同类型的类,熟练掌握类属性、实例属性、实例方法、类方法、静态方法的使用场景。理解面向对象编程的核心思想。

« 上一篇 面向对象编程概述 下一篇 » 构造方法__init__