news 2026/7/7 7:26:45

Python面向对象进阶:__slots__、@property、枚举类、元类到底是什么?一篇彻底讲明白!(小白必看) (六.1)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python面向对象进阶:__slots__、@property、枚举类、元类到底是什么?一篇彻底讲明白!(小白必看) (六.1)

目录

一、__slots__:为什么对象可以随便增加属性?

1.1 __slots__ 怎么使用?

1.2 用生活中的例子理解 __slots__

1.3 __slots__ 还能节省内存

1.4 __slots__ 有没有缺点?

1.5 __slots__ 需要注意的一点

本节小结

二、@property:为什么别人家的属性既安全,用起来还像普通变量?

2.1 为什么不能让别人直接修改属性?

2.2 第一种解决方案:使用 get 和 set 方法

2.3 @property 到底是什么?

2.4 @property 到底做了什么?

2.5 @property 可以理解成"门卫"

2.6 为什么还要写 @score.setter?

2.7 实际开发中为什么喜欢用 @property?

本节小结

本章节篇幅较多,后续‘枚举类、元类’等内容可在 六.2 章节进行阅读学习,感谢您的点赞,关注和收藏!!


前面的几篇文章,我们已经学习了 Python 面向对象编程的基础知识,例如:

  • 类(Class)

  • 对象(Object)

  • 属性和方法

  • 继承

  • 多态

相信大家已经能够写出一个简单的类了,例如:

class Student: def __init__(self, name, age): self.name = name self.age = age def introduce(self): print(f"大家好,我叫{self.name},今年{self.age}岁。")

创建对象:

s = Student("张三",18) s.introduce()

输出:

大家好,我叫张三,今年18岁。

是不是已经有点像那么回事了?但是,如果你真正开始写项目,很快就会发现新的问题。

例如:

  • 为什么对象可以随便增加属性?

  • 怎样才能保证数据不会被别人乱改?

  • 为什么别人写的对象还能直接使用len()print()

  • 为什么有些类还能同时继承多个父类?

  • 元类到底是什么?网上教程为什么越看越迷糊?

别着急,今天这篇文章,我们继续学习 Python 面向对象编程中的几个进阶知识。虽然名字看起来有点高深,但实际上,每一个知识点都是为了解决实际开发中的问题。理解了它们,你写出来的代码会更加规范,也更接近真正的 Python 开发方式。

一、__slots__:为什么对象可以随便增加属性?

先来看一个非常神奇的现象,上一篇文章,我们创建过一个学生类:

class Student: pass

注意,这个类里面什么都没有。现在创建对象:

s = Student()

接下来,我们给它添加一个属性:

s.name = "张三"

打印一下:

print(s.name)

输出:

张三

没有任何问题,继续添加:

s.age = 18 s.score = 98 s.address = "北京" s.phone = "123456789"

再次运行,依然没有报错。很多小白第一次看到这里都会觉得:

Python 这么随意的吗?

没错,Python 的对象就是这么自由。你想什么时候增加属性,就什么时候增加。甚至:

s.game = "王者荣耀" s.favorite_food = "火锅"

都没有问题。自由虽然爽,但问题也来了,来看下面这段代码:

class Student: pass s = Student() s.name = "张三" print(s.name)

没有问题,但是如果哪天手滑了写成:

s.nmae = "张三"

注意!这里不是:

name

而是:

nmae

很多语言会直接报错,但是 Python 不会,因为 Python 认为:

哦,你不是写错了。

你只是新增了一个叫nmae的属性。

于是,对象里面真的多了一个:

nmae

程序还能继续运行,结果等你调试两个小时以后才发现,原来只是拼错了一个字母……

相信很多 Python 程序员都经历过这种"社死现场"。那怎么办?

如果一个对象只能拥有固定几个属性,是不是就不会出现这种问题了?答案就是:

__slots__

它的作用只有一句话:

限制对象能够拥有哪些属性。

1.1 __slots__怎么使用?

例如:

class Student: __slots__ = ("name", "age")

这里只有两个属性:

  • name

  • age

创建对象:

s = Student()

赋值:

s.name = "张三" s.age = 18

都没有问题,但是如果继续:

s.score = 100

程序会直接报错:

AttributeError

意思就是:

对不起。

score 不允许存在。

为什么会报错?因为:

__slots__ = ("name","age")

已经提前告诉 Python,这个类以后只能拥有:

name age

除此之外任何新的属性统统不允许,这样一来,如果你再写:

s.nmae = "张三"

程序会立刻报错,你马上就知道~哦,原来我拼写错了,而不是等程序运行半天以后才发现。

1.2 用生活中的例子理解__slots__

假设学校发给你一张学生信息登记表,上面只有几个栏目:

姓名: 年龄: 班级:

老师说,只能填写这些。结果你在下面又写了:

游戏段位: 微博账号: 外卖地址:

老师肯定会说:

同学,这不是你自由发挥的时候。

表格上没有这一栏。

__slots__就相当于这张固定格式的表格。它规定了:

哪些信息可以填写。

哪些信息不能填写。

1.3 __slots__还能节省内存

除了限制属性之外,__slots__还有一个优点。

节省内存。

为什么?因为普通对象会专门留出一块空间。记录:

我有哪些属性?

如果对象很多,如:

100万个对象

这些记录也会占用不少内存,而:

__slots__

提前告诉 Python:

属性只有这几个。

Python 就不用再额外记录,所以会节省一些内存。

当然,对于刚开始学习 Python 的同学来说,这一点了解即可。真正写大型项目的时候,你才会真正体会到它的优势。

1.4 __slots__有没有缺点?

当然有,最大的缺点就是:

不够灵活。

例如,以前你可以随时增加属性:

s.score = 98

现在不行了,如果以后需求变化,又想增加:

score

怎么办?只能修改:

__slots__ = ("name","age","score")

重新定义。

所以:__slots__并不是所有类都要使用。它更适合那些:

属性固定、不会频繁变化的类。

例如:

  • 身份证信息

  • 商品信息

  • 配置信息

这些数据通常比较固定,使用__slots__会更加规范。

1.5 __slots__需要注意的一点

还有一个容易踩坑的地方,来看下面的代码:

class Student: __slots__ = ("name",) class GoodStudent(Student): pass

创建子类对象:

g = GoodStudent() g.name = "张三" g.score = 100

很多同学会以为,这里会报错。其实不会,为什么?

因为:

__slots__默认只对当前类生效。

子类如果没有定义__slots__,依然可以动态添加新的属性。如果希望子类也受到限制,就需要在子类中继续定义__slots__。这一点初学者记住即可,真正开发中遇到再深入研究也不迟。

本节小结

今天我们学习了一个新的知识点:

__slots__

它主要有两个作用:

限制对象能够拥有的属性。

节省对象占用的内存。

对于初学者来说,只需要记住一句话:

__slots__就像给对象制定了一份"属性名单",名单之外的属性,一律不允许添加。

理解这一点,以后看到别人代码里的__slots__,就不会再觉得神秘了。

二、@property:为什么别人家的属性既安全,用起来还像普通变量?

上一篇文章,我们学过私有属性。例如:

class Student: def __init__(self): self.__score = 0

这里的:

__score

就是一个私有属性,外部不能直接访问:

s = Student() print(s.__score)

运行后会报错:

AttributeError

很多小伙伴看到这里可能会想:

那我以后怎么查看成绩?

总不能创建了一个对象,里面的数据自己都看不到吧?当然不是。

Python 给我们提供了一种更加安全的方法。

2.1 为什么不能让别人直接修改属性?

假设你正在开发一个学生管理系统,每个学生都有一个成绩。最简单的写法就是:

class Student: def __init__(self): self.score = 0

创建对象:

s = Student()

修改成绩:

s.score = 95

没有任何问题,但是……如果有人这样写呢?

s.score = -100

或者:

s.score = 999

程序同样不会报错,可是现实中,考试成绩怎么可能是:

-100分

或者:

999分

这明显是不合理的,所以我们需要一种办法:

在修改数据之前,先检查数据是否合法。

2.2 第一种解决方案:使用 get 和 set 方法

很多编程语言都会采用这种方式,例如:

class Student: def __init__(self): self.__score = 0 def set_score(self, score): if 0 <= score <= 100: self.__score = score else: print("成绩必须在0~100之间") def get_score(self): return self.__score

创建对象:

s = Student()

修改成绩:

s.set_score(95)

查看成绩:

print(s.get_score())

输出:

95

如果输入:

s.set_score(200)

输出:

成绩必须在0~100之间

是不是安全多了?因为所有的数据,都必须经过:

set_score()

这个方法,只有检查通过才能真正修改。

但是,这种写法有一个缺点,大家有没有觉得:这样写有点麻烦?

以前:

s.score = 95

一句话搞定。现在变成:

s.set_score(95)

读取又变成:

s.get_score()

每次都要:

get... set...

写多了也挺累,于是 Python 想:

有没有办法既能保证安全,又能让代码看起来像普通属性?

答案就是:

@property

2.3 @property 到底是什么?

一句话理解:

它可以把一个方法,伪装成一个普通属性。

是不是有点绕?没关系,直接看代码。

class Student: def __init__(self): self.__score = 0 @property def score(self): return self.__score @score.setter def score(self, value): if 0 <= value <= 100: self.__score = value else: print("成绩必须在0~100之间")

创建对象:

s = Student()

修改成绩:

s.score = 90

读取成绩:

print(s.score)

输出:

90

有没有发现?代码看起来和普通属性一模一样。

但是实际上,Python 已经偷偷帮我们完成了数据检查。

2.4 @property 到底做了什么?

很多小白第一次学习这里都会觉得:

我明明写的是:

s.score = 90

为什么会执行:

def score(self, value):

其实执行流程是这样的:

s.score = 90 ↓ Python发现score有@property ↓ 自动调用setter方法 ↓ 检查数据是否合法 ↓ 合法才真正修改

所以,你以为自己修改的是属性。实际上修改的是一个方法,是不是有点神奇?

2.5 @property 可以理解成"门卫"

假设有一个小区,居民想进入。看起来:都是直接走进去。实际上,门口一直站着一个保安。

流程是:

居民 ↓ 保安检查 ↓ 身份正常 ↓ 放行

如果身份异常:

居民 ↓ 保安 ↓ 拦住

@property 就像这个保安,你觉得自己是在直接访问:

score

实际上,Python 已经偷偷帮你检查了一遍。

2.6 为什么还要写 @score.setter?

很多同学又有疑问,为什么不是:

@property

一个就够了?原因很简单。读取和修改是两件不同的事情。例如,查看成绩:

print(s.score)

Python 会调用:

@property def score(self):

返回成绩。

而:

s.score = 90

Python 会调用:

@score.setter

修改成绩。所以,一个负责:

读取。

一个负责:

修改。

分工明确。

还能创建只读属性,有时候我们希望别人只能查看,不能修改。

例如:

学生学号。

身份证号码。

订单编号。

这些数据创建以后,一般不会修改,那么只写:

@property

即可。例如:

class Student: def __init__(self): self.__id = "20250001" @property def student_id(self): return self.__id

读取:

print(s.student_id)

可以,但是:

s.student_id = "8888"

程序会直接报错,因为没有:

@student_id.setter

所以这个属性就是:

只读属性。

2.7 实际开发中为什么喜欢用 @property?

因为,它同时拥有两个优点。

第一:使用方便,代码像普通变量一样:

s.score = 95

第二:数据安全,程序内部已经偷偷完成检查。

所以现在很多 Python 框架都会大量使用:

@property

你以后阅读别人代码的时候,几乎天天都会遇见它。

本节小结

这一节,我们学习了 Python 中一个非常重要的知识点:

@property

它最大的作用就是:

让方法拥有属性一样的使用方式。

简单来说:

  • @property:负责获取属性值。

  • @xxx.setter:负责修改属性值。

  • 可以在修改数据时进行合法性检查。

  • 如果不写setter,属性就是只读的。

对于初学者来说,只需要记住一句话:

@property的本质并不是普通属性,而是把方法"包装"成了属性,让代码既优雅又安全。

本章节篇幅较多,后续‘枚举类、元类’等内容可在 六.2 章节进行阅读学习,感谢您的点赞,关注和收藏!!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 7:25:14

终极RPG Maker解密工具:轻松提取加密游戏资源的完整指南

终极RPG Maker解密工具&#xff1a;轻松提取加密游戏资源的完整指南 【免费下载链接】RPGMakerDecrypter Tool for decrypting and extracting RPG Maker XP, VX and VX Ace encrypted archives and MV and MZ encrypted files. 项目地址: https://gitcode.com/gh_mirrors/rp…

作者头像 李华
网站建设 2026/7/7 7:26:32

VASP结构优化保姆级教程:从POSCAR到CONTCAR,手把手搞定ISIF参数设置

VASP结构优化实战指南&#xff1a;从晶体文件到稳定构型的全流程解析在计算材料科学领域&#xff0c;VASP作为第一性原理计算的黄金标准工具&#xff0c;其结构优化功能是每位研究者必须掌握的核心技能。本文将带您系统掌握从初始结构准备到最终结果分析的完整流程&#xff0c;…

作者头像 李华
网站建设 2026/7/3 23:43:28

ABAP GUID/UUID生成实战:从基础概念到S/4 HANA与ECC版本适配

1. GUID/UUID基础概念解析 第一次接触GUID这个概念时&#xff0c;我也被它那一长串字母数字搞懵了。简单来说&#xff0c;GUID&#xff08;全局唯一标识符&#xff09;就像给数据对象发的身份证号&#xff0c;保证在全球范围内都不会重复。在ABAP开发中&#xff0c;我们经常需要…

作者头像 李华
网站建设 2026/7/3 10:34:48

太阳能控制器定做厂家的工艺选型与工程应用要点解析

一、引言&#xff1a;定制化时代的工艺门槛当前太阳能控制器市场正经历从“标准化通用品”向“场景化定制件”的深度转型。对于工程应用而言&#xff0c;采购方已不再仅关注标称电流电压参数&#xff0c;而是要求控制器在恶劣气候、复杂负载、偏远运维条件下具备极高的环境适应…

作者头像 李华