第60集:类属性与实例属性

学习目标

  • 理解类属性与实例属性的区别
  • 掌握类属性的访问和修改方式
  • 学会合理使用类属性和实例属性
  • 理解类方法、实例方法和静态方法的区别
  • 掌握属性的查找顺序

一、类属性与实例属性概述

1.1 类属性

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

1.2 实例属性

实例属性:定义在方法中,使用self绑定的变量,每个对象独立。

1.3 基本示例

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

dog1 = Dog("旺财", 3)
dog2 = Dog("来福", 5)

print(dog1.species)  # 输出:犬科动物
print(dog2.species)  # 输出:犬科动物
print(Dog.species)   # 输出:犬科动物

print(dog1.name)     # 输出:旺财
print(dog2.name)     # 输出:来福

二、类属性详解

2.1 定义类属性

class Circle:
    pi = 3.14159  # 类属性:圆周率
    count = 0     # 类属性:计数器

print(f"π = {Circle.pi}")
print(f"计数: {Circle.count}")

2.2 访问类属性

class Student:
    school = "Python学院"  # 类属性
    count = 0               # 学生计数

# 通过类访问
print(Student.school)  # 输出:Python学院

# 通过对象访问
stu1 = Student()
print(stu1.school)  # 输出:Python学院

# 所有对象共享类属性
stu2 = Student()
print(f"stu1.school: {stu1.school}")
print(f"stu2.school: {stu2.school}")

2.3 修改类属性

class Product:
    discount_rate = 0.1  # 默认折扣率

print(f"默认折扣: {Product.discount_rate}")

# 通过类修改
Product.discount_rate = 0.15
print(f"修改后折扣: {Product.discount_rate}")

# 所有对象都看到修改后的值
p1 = Product()
p2 = Product()
print(f"p1折扣: {p1.discount_rate}")
print(f"p2折扣: {p2.discount_rate}")

2.4 注意:通过对象修改类属性

class Counter:
    count = 0

counter = Counter()

# 通过对象赋值会创建实例属性
counter.count = 10

print(f"Counter.count: {Counter.count}")  # 输出:0
print(f"counter.count: {counter.count}")  # 输出:10

# 实例属性遮蔽了类属性

三、实例属性详解

3.1 定义实例属性

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

person = Person("张三", 25)
print(f"姓名: {person.name}")
print(f"年龄: {person.age}")

3.2 动态添加实例属性

class Book:
    pass

book = Book()

# 动态添加属性
book.title = "Python编程"
book.author = "张三"
book.price = 59.9

print(f"书名: {book.title}")
print(f"作者: {book.author}")
print(f"价格: {book.price}元")

3.3 每个对象的实例属性独立

class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

stu1 = Student("张三", 90)
stu2 = Student("李四", 85)

# 修改stu1的分数
stu1.score = 95

print(f"stu1分数: {stu1.score}")  # 输出:95
print(f"stu2分数: {stu2.score}")  # 输出:85(不受影响)

四、属性查找顺序

4.1 查找顺序

实例对象 → 实例属性 → 类属性 → 父类属性 → object

4.2 查找示例

class MyClass:
    class_var = "类属性"

obj = MyClass()

# 1. 添加同名实例属性
obj.class_var = "实例属性"

print(obj.class_var)   # 输出:实例属性(实例属性遮蔽类属性)
print(MyClass.class_var)  # 输出:类属性

# 2. 删除实例属性
del obj.class_var
print(obj.class_var)   # 输出:类属性(回到类属性)

4.3 完整查找示例

class Parent:
    var = "父类属性"

class Child(Parent):
    var = "子类属性"

obj = Child()

# 查找顺序
print(obj.var)           # 输出:子类属性
print(Child.var)         # 输出:子类属性
print(Parent.var)        # 输出:父类属性

五、使用类属性实现计数

5.1 对象计数器

class Item:
    count = 0  # 类属性:计数器
    
    def __init__(self, name):
        self.name = name
        Item.count += 1  # 创建对象时计数加1
    
    def __del__(self):
        Item.count -= 1  # 删除对象时计数减1

print(f"创建前: {Item.count}个对象")

item1 = Item("商品1")
item2 = Item("商品2")
item3 = Item("商品3")

print(f"创建后: {Item.count}个对象")

del item1
print(f"删除一个后: {Item.count}个对象")

5.2 生成唯一ID

class User:
    next_id = 1  # 下一个可用的ID
    
    def __init__(self, name):
        self.name = name
        self.id = User.next_id
        User.next_id += 1
    
    def __str__(self):
        return f"ID: {self.id}, 姓名: {self.name}"

users = [User("张三"), User("李四"), User("王五")]
for user in users:
    print(user)

六、类属性的实际应用

6.1 配置管理

class Config:
    """配置类"""
    DEBUG = True
    MAX_CONNECTIONS = 100
    TIMEOUT = 30
    LOG_LEVEL = "INFO"

# 使用配置
print(f"调试模式: {Config.DEBUG}")
print(f"最大连接数: {Config.MAX_CONNECTIONS}")

# 修改配置
Config.DEBUG = False
print(f"修改后调试模式: {Config.DEBUG}")

6.2 常量定义

class MathConstants:
    """数学常量"""
    PI = 3.141592653589793
    E = 2.718281828459045
    GOLDEN_RATIO = 1.618033988749895

print(f"π = {MathConstants.PI}")
print(f"e = {MathConstants.E}")
print(f"黄金分割 = {MathConstants.GOLDEN_RATIO}")

6.3 缓存管理

class Cache:
    """缓存类"""
    _cache = {}  # 私有类属性
    
    @classmethod
    def get(cls, key):
        return cls._cache.get(key)
    
    @classmethod
    def set(cls, key, value):
        cls._cache[key] = value
    
    @classmethod
    def clear(cls):
        cls._cache.clear()
    
    @classmethod
    def show(cls):
        print(f"缓存内容: {cls._cache}")

# 使用缓存
Cache.set("user:1", {"name": "张三", "age": 25})
Cache.set("user:2", {"name": "李四", "age": 30})

Cache.show()

user = Cache.get("user:1")
print(f"用户1: {user}")

七、类方法与实例方法

7.1 实例方法

class Calculator:
    def __init__(self):
        self.result = 0
    
    def add(self, a, b):  # 实例方法
        self.result = a + b
        return self.result

calc = Calculator()
print(calc.add(3, 5))  # 输出:8

7.2 类方法

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    
    @classmethod
    def today(cls):
        import datetime
        today = datetime.date.today()
        return cls(today.year, today.month, today.day)
    
    @classmethod
    def from_string(cls, date_str):
        year, month, day = map(int, date_str.split('-'))
        return cls(year, month, day)

today = Date.today()
print(f"今天: {today.year}-{today.month}-{today.day}")

date = Date.from_string("2024-12-25")
print(f"指定日期: {date.year}-{date.month}-{date.day}")

7.3 静态方法

class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b
    
    @staticmethod
    def multiply(a, b):
        return a * b

print(MathUtils.add(3, 5))       # 输出:8
print(MathUtils.multiply(3, 5))  # 输出:15

八、属性装饰器

8.1 @property装饰器

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def celsius(self):
        """获取摄氏度"""
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        """设置摄氏度"""
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        self._celsius = value
    
    @property
    def fahrenheit(self):
        """获取华氏度(只读)"""
        return self._celsius * 9/5 + 32

temp = Temperature(25)
print(f"摄氏度: {temp.celsius}°C")
print(f"华氏度: {temp.fahrenheit:.1f}°F")

temp.celsius = 30
print(f"修改后摄氏度: {temp.celsius}°C")

九、常见错误与注意事项

9.1 常见错误

  1. 通过对象修改类属性:
class Counter:
    count = 0

c1 = Counter()
c2 = Counter()

c1.count = 10  # 创建实例属性
print(c1.count)  # 输出:10
print(c2.count)  # 输出:0
print(Counter.count)  # 输出:0
  1. 忘记使用类名:
class MyClass:
    value = 0

    def method(self):
        value += 1  # 错误!应该用 self.value 或 MyClass.value

9.2 注意事项

  1. 类属性被所有对象共享
  2. 实例属性每个对象独立
  3. 通过对象修改类属性会创建实例属性
  4. 合理使用类属性存储共享数据
  5. 使用实例属性存储对象特有数据

十、课后练习

练习题

  1. 编程题

    • 定义一个Person类
    • 使用类属性计数人数
    • 每创建一个对象人数加1
  2. 编程题

    • 定义一个配置类
    • 使用类属性存储配置
    • 提供修改配置的方法
  3. 思考题

    • 类属性和实例属性有什么区别?
    • 什么时候应该使用类属性?
    • 属性的查找顺序是什么?

十一、本集总结

核心知识点回顾

  1. 类属性:定义在类中,所有对象共享
  2. 实例属性:定义在实例中,每个对象独立
  3. 属性查找:实例→类→父类→object
  4. 类方法:使用@classmethod,操作类属性
  5. 静态方法:使用@staticmethod,不依赖实例或类
  6. 属性装饰器:@property实现属性访问控制

下集预告

下一集我们将学习面向对象高级特性,包括静态方法、类方法、属性装饰器等。


学习建议: 理解类属性和实例属性的区别非常重要,合理使用可以提高代码的效率和可维护性。

« 上一篇 多态特性 下一篇 » 静态方法与类方法