当前位置: 首页 > news >正文

Python 实例属性和类属性

Python 的类和对象是面向对象编程的核心,而属性(attributes)是类和对象中存储数据的地方。Python 的属性分为实例属性类属性,这俩虽然听起来差不多,但用法和行为有挺大的区别。

参考文章:Python 实例属性和类属性 | 简单一点学习 easyeasy.me

1. 什么是实例属性和类属性?

1.1 实例属性

实例属性是属于某个具体对象(实例)的属性。每个对象都有自己的实例属性,互不干扰。就像你和你的朋友每人有自己的手机,手机里的照片、设置啥的都是独一无二的。

  • 特点
    • 通常在 __init__ 方法中通过 self 定义。
    • 每个实例的属性值可以不同。
    • 只能通过实例访问(obj.attribute)。

1.2 类属性

类属性是属于整个类的属性,所有实例共享同一份数据。就像一个班级的班规,所有学生都得遵守同一套规则。

  • 特点
    • 定义在类内部,但不在任何方法内(通常在类开头定义)。
    • 通过类名或实例都可以访问(ClassName.attributeobj.attribute)。
    • 修改类属性会影响所有实例(除非实例覆盖了它)。

2. 怎么定义和使用这两种属性?

2.1 定义实例属性

实例属性一般在 __init__ 方法里用 self 来定义,每次创建对象时都会初始化。

class Dog:def __init__(self, name, age):self.name = name  # 实例属性self.age = age    # 实例属性# 创建两个 Dog 实例
dog1 = Dog("旺财", 3)
dog2 = Dog("小黑", 5)print(dog1.name)  # 输出: 旺财
print(dog2.name)  # 输出: 小黑

上面代码里,nameage 是实例属性,dog1dog2 各有一份,互不影响。

2.2 定义类属性

类属性直接在类里定义,不需要 self,通常放在 __init__ 方法外面。

class Dog:species = "Canis familiaris"  # 类属性def __init__(self, name, age):self.name = nameself.age = agedog1 = Dog("旺财", 3)
dog2 = Dog("小黑", 5)print(dog1.species)  # 输出: Canis familiaris
print(dog2.species)  # 输出: Canis familiaris
print(Dog.species)   # 输出: Canis familiaris

species 是类属性,dog1dog2Dog 类都能访问它,因为它是所有实例共享的。

3. 访问和修改属性的区别

3.1 访问属性

  • 实例属性:只能通过实例访问,比如 dog1.name
  • 类属性:可以通过类名(Dog.species)或实例(dog1.species)访问。
class Dog:species = "Canis familiaris"def __init__(self, name):self.name = namedog = Dog("旺财")
print(dog.name)      # 实例属性,输出: 旺财
print(dog.species)   # 类属性,输出: Canis familiaris
print(Dog.species)   # 类属性,输出: Canis familiaris

3.2 修改属性

  • 实例属性:修改只影响当前实例。
  • 类属性:通过类名修改会影响所有实例;通过实例修改会“遮盖”类属性(实际上是为实例创建了一个同名的实例属性)。
class Dog:species = "Canis familiaris"def __init__(self, name):self.name = namedog1 = Dog("旺财")
dog2 = Dog("小黑")# 修改类属性
Dog.species = "Canis lupus"
print(dog1.species)  # 输出: Canis lupus
print(dog2.species)  # 输出: Canis lupus# 通过实例“修改”类属性(实际上创建了实例属性)
dog1.species = "Doggo"
print(dog1.species)  # 输出: Doggo(实例属性)
print(dog2.species)  # 输出: Canis lupus(类属性)
print(Dog.species)   # 输出: Canis lupus(类属性)

注意:dog1.species = "Doggo" 并不是修改了类属性,而是给 dog1 创建了一个新的实例属性 species,遮盖了类属性。

4. 实际场景中的用法

4.1 实例属性的典型场景

实例属性适合存储每个对象独有的数据,比如名字、年龄、ID 等等。就像下面这个例子:

class Student:def __init__(self, name, student_id):self.name = nameself.student_id = student_idself.grades = []def add_grade(self, grade):self.grades.append(grade)student1 = Student("小明", "001")
student2 = Student("小红", "002")student1.add_grade(90)
student2.add_grade(85)print(student1.grades)  # 输出: [90]
print(student2.grades)  # 输出: [85]

每个学生有自己的成绩单,互不干扰,这就是实例属性的典型用法。

4.2 类属性的典型场景

类属性适合存储所有实例共享的数据,比如计数器、默认配置等。比如下面这个例子,用类属性来统计创建了多少个对象:

class Dog:count = 0  # 类属性,用来计数def __init__(self, name):self.name = nameDog.count += 1  # 每次创建实例,计数加 1dog1 = Dog("旺财")
dog2 = Dog("小黑")
dog3 = Dog("大黄")print(Dog.count)  # 输出: 3

count 是类属性,记录了总共创建了多少只狗,所有的狗共享这个计数器。

5. 注意事项和常见坑

5.1 实例属性和类属性的命名冲突

如果实例属性和类属性同名,实例属性会“遮盖”类属性。前面已经看到过例子了,这种情况要小心,别搞混了。

5.2 可变类属性的陷阱

如果类属性是可变对象(比如列表或字典),所有实例共享同一份数据,修改会影响所有实例。

class Dog:tricks = []  # 类属性,是一个列表def __init__(self, name):self.name = namedef add_trick(self, trick):self.tricks.append(trick)dog1 = Dog("旺财")
dog2 = Dog("小黑")dog1.add_trick("坐下")
dog2.add_trick("握手")print(dog1.tricks)  # 输出: ['坐下', '握手']
print(dog2.tricks)  # 输出: ['坐下', '握手']

这可能不是你想要的!因为 tricks 是类属性,所有狗共享同一个列表。如果你想要每只狗有自己的技能列表,应该用实例属性:

class Dog:def __init__(self, name):self.name = nameself.tricks = []  # 实例属性def add_trick(self, trick):self.tricks.append(trick)dog1 = Dog("旺财")
dog2 = Dog("小黑")dog1.add_trick("坐下")
dog2.add_trick("握手")print(dog1.tricks)  # 输出: ['坐下']
print(dog2.tricks)  # 输出: ['握手']

5.3 动态添加实例属性

Python 允许动态给实例添加属性,但要小心,这可能会让代码不好维护。

class Dog:def __init__(self, name):self.name = namedog = Dog("旺财")
dog.age = 3  # 动态添加实例属性
print(dog.age)  # 输出: 3

虽然很灵活,但建议尽量在 __init__ 里定义所有属性,保持代码清晰。

6. 总结

  • 实例属性:每个对象独有,定义在 __init__ 里,用 self 访问,适合存储对象特有的数据。
  • 类属性:所有实例共享,定义在类里,用类名或实例访问,适合存储共享数据。
  • 注意事项:小心命名冲突和可变类属性的陷阱,尽量在 __init__ 里定义实例属性。
http://www.dtcms.com/a/324966.html

相关文章:

  • 【PyTorch】单目标检测项目
  • vulnhub-Drippingblues靶机
  • Typora结合PicGo + 使用Gitee搭建个人免费图床
  • 计算机网络---IP(互联网协议)
  • 2025年6月电子学会全国青少年软件编程等级考试(Python六级)真题及答案
  • 二叉树进阶 之 【二叉搜索树的简介与模拟实现的前提准备】
  • 【杂谈】-智能代理+可观察性:构建下一代复杂系统监控体系
  • UE5多人MOBA+GAS 41、制作一个飞弹,添加准心索敌
  • JS实现数组扁平化
  • 计算二分类误差时的常见错误及解决方案
  • ubuntu22.04+samba
  • VMware 使用 Ubuntu 一段时间后逐渐卡顿、甚至卡死的问题
  • sqli-labs-master/Less-51~Less-61
  • 解读 GPT-5:从“博士级 AI 专家”能力到 OpenAI API Key 获取与实践(提示工程→性能调优全流程)
  • MySQL自增ID与UUID的区别及其在索引分裂中的表现与优化
  • W3D引擎游戏开发----从入门到精通【23】
  • 2013年考研数学(二)真题
  • A#语言详解
  • 相比于传统的全波分析,特征模分析具有哪些优点
  • vue如何监听localstorage
  • 博览会(树形DP)
  • 机器学习——标准化、归一化
  • Spring Boot 事务详解:原理与实操指南
  • AQS(AbstractQueuedSynchronizer)底层源码实现与设计思想
  • 第三章-提示词:从0到1,提示词实训全攻略,解锁大语言模型无限潜能(14/36)
  • MyBatis Mapper核心组件协作关系深度解析
  • Java条件判断与用户交互实战案例
  • 【经典算法】二叉树最小深度详解:递归解法与可视化分析
  • 深入解析C#并行编程:从并行循环到异步编程模式
  • PyCATIA深度解析:基于装配截面自动化创建参考几何平面群的专业方案