三大特征
【引】属性查找顺序
- 对象的名称空间里只存放着对象独有的属性,而对象们相似的属性是存放于类中的。
- 对象在访问属性时,会优先从对象本身的
__dict__
中查找,未找到,则去类的__dict__
中查找
封装
【一】概要
- 封装是将数据和操作数据的方法打包在一个单元(类)中,实现数据隐藏、代码组织、隔离变化的目的。这使得对象的内部实现细节对外部用户不可见,同时提供了清晰的接口供外部代码使用。
- 通俗来讲,封装就是一种思想,将数据和功能整合到一起,也就是“整合”代码。
- 针对封装到对象或者类中的属性,我们还可以严格控制对它们的访问,分两步实现:隐藏和开放接口
【二】常用方法
- 隐藏
- 开放接口
- 隐藏后的属性具有私有性,对于外部是隐藏的,对于内部是开放的,通过暴露接口来使外界访问
【三】详解
- 模块化组织: 封装有助于将代码划分为相对独立、可重用的模块。每个模块都可以包含特定功能的一组类、函数或变量,使得代码结构更加清晰,易于维护。
- 隐藏实现细节: 封装允许将对象的内部实现细节隐藏起来,只暴露必要的接口。这样,其他部分的代码不需要关心对象内部是如何实现的,只需要通过公共接口与对象进行交互。这种隐藏减少了代码之间的耦合性,提高了代码的可维护性和可扩展性。
- 信息隐藏: 封装还提供了对对象内部信息的控制能力。通过将数据成员设为私有,只能通过公共方法进行访问,可以确保对数据的修改和访问都经过一定的逻辑控制,增强了程序的健壮性。
【1】隐藏属性
| class Class(object): |
| name = 'user' |
| |
| def func(self): |
| print('实例方法') |
| |
| @classmethod |
| def func1(cls): |
| print('类方法') |
| |
| @staticmethod |
| def func2(): |
| print('静态方法') |
| |
| '''正常情况下,通过类名+【.】都是可以访问到属性的''' |
| print(Class.name) |
| print(Class.func(self=Class())) |
| print(Class.func1()) |
| print(Class.func2()) |
| class Class(object): |
| _name = 'user001' |
| __name = 'user' |
| |
| def __func(self): |
| print('实例方法') |
| |
| @classmethod |
| def __func1(cls): |
| print('类方法') |
| |
| @staticmethod |
| def __func2(): |
| print('静态方法') |
| |
| |
| '''通过单下划线并不能实现隐藏属性,外界依旧可以访问的到''' |
| print(Class._name) |
| print(Class.__name) |
| print(Class.__func(self=Class())) |
| print(Class.__func1()) |
| print(Class.__func2()) |
【1.1】实现隐藏的本质:变形
| class Class(object): |
| _name = 'user001' |
| __name = 'user' |
| |
| def __func(self): |
| print('实例方法') |
| |
| |
| print(Class.__dict__) |
| |
| '''通过【_类名__属性名】是可以拿到值的''' |
| print(Class._Class__name) |
| |
| '''是可以通过变形后的名称对属性进行修改的''' |
| print(Class._Class__name) |
| Class._Class__name = 'user002' |
| print(Class._Class__name) |
| |
| '''但是不可以通过【__属性名】为其添加隐藏属性''' |
| Class.__age = 20 |
| print(Class._Class__age) |
| |
| '''再次查看名称空间可以发现,是新增了一个键为【__age】,而不是同上述的隐藏属性进行了变形''' |
| print(Class.__dict__) |
| '''由此可知,变形只在定义类的时候触发''' |
- 以上是类中的隐藏属性,也可以通过
__init__
为对象添加自己的隐藏属性
| class Class(object): |
| |
| def __init__(self,name,age): |
| self.__name = name |
| self.__age = age |
| |
| c=Class(name='001',age=18) |
| |
| |
| print(c.__dict__) |
| |
【2】开放接口
- 隐藏后的属性具有私有性,对于外部是隐藏的,对于内部是开放的,通过暴露接口来使外界访问
| class Class(object): |
| _name = 'user001' |
| __name = 'user' |
| |
| def __func(self): |
| print('实例方法') |
| |
| @classmethod |
| def __func1(cls): |
| print('类方法') |
| |
| @staticmethod |
| def __func2(): |
| print('静态方法') |
| |
| |
| def main(self): |
| '''开放的接口''' |
| func_choice = input("请输入想要使用的功能:").strip() |
| if func_choice == 'func': |
| |
| self.__func() |
| elif func_choice == 'func1': |
| |
| self.__func1() |
| elif func_choice == 'func2': |
| |
| self.__func2() |
| else: |
| |
| print(self.__name) |
| |
| |
| Class.main(self=Class()) |
- main函数就是作为接口开放给外界的,可以通过main来调用到类中的隐藏属性
【2.1】封装的隔离变化作用
| class Class(object): |
| _name = 'user001' |
| __name = 'user' |
| |
| def __func(self): |
| print('实例方法') |
| print("我可以对函数随意改变,只要不修改传参的内容和返回值,接口都不需要修改") |
| |
| @classmethod |
| def __func1(cls): |
| print(cls._name) |
| print("我可以对函数随意改变,只要不修改传参的内容和返回值,接口都不需要修改") |
| |
| @staticmethod |
| def __func2(): |
| print(Class.__name) |
| print('func2') |
| '''我可以对函数随意改变,只要不修改传参的内容和返回值,接口都不需要修改''' |
| |
| |
| def main(self): |
| '''开放的接口''' |
| func_choice = input("请输入想要使用的功能:").strip() |
| if func_choice == 'func': |
| |
| self.__func() |
| elif func_choice == 'func1': |
| |
| self.__func1() |
| elif func_choice == 'func2': |
| |
| self.__func2() |
| else: |
| |
| print(self.__name) |
| |
| |
| Class.main(self=Class()) |
【3】扩展:装饰器@property
- property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
- 通俗来讲,就是将一个方法(函数属性)包装成数据属性
| |
| class property(object): |
| """ |
| Property attribute. |
| # 属性装饰器。 |
| |
| fget |
| function to be used for getting an attribute value |
| fset |
| function to be used for setting an attribute value |
| fdel |
| function to be used for del'ing an attribute |
| doc |
| docstring |
| |
| Typical use is to define a managed attribute x: |
| # 典型的用法是定义一个受管理的属性 x: |
| |
| class C(object): |
| def getx(self): return self._x |
| def setx(self, value): self._x = value |
| def delx(self): del self._x |
| x = property(getx, setx, delx, "I'm the 'x' property.") |
| |
| Decorators make defining new properties or modifying existing ones easy: |
| # 使用装饰器可以更轻松地定义新属性或修改现有属性: |
| |
| class C(object): |
| @property |
| def x(self): |
| "I am the 'x' property." |
| return self._x |
| @x.setter |
| def x(self, value): |
| self._x = value |
| @x.deleter |
| def x(self): |
| del self._x |
| """ |
| def deleter(self, *args, **kwargs): |
| """ Descriptor to obtain a copy of the property with a different deleter. """ |
| """ 用于获取具有不同删除器的属性副本的描述符。 """ |
| pass |
| |
| def getter(self, *args, **kwargs): |
| """ Descriptor to obtain a copy of the property with a different getter. """ |
| """ 用于获取具有不同获取器的属性副本的描述符。 """ |
| pass |
| |
| def setter(self, *args, **kwargs): |
| """ Descriptor to obtain a copy of the property with a different setter. """ |
| """ 用于获取具有不同设置器的属性副本的描述符。 """ |
| pass |
【3.1】@property
的具体用法
| '''基本用法''' |
| class Class(object): |
| __name = "user001" |
| |
| @property |
| def get_name(self): |
| return self.__name |
| |
| print(Class().get_name) |
| '''具体案例''' |
| |
| |
| '''不加property''' |
| class Person(object): |
| def __init__(self, height, weight): |
| '''初始化得到对象的身高体重''' |
| self.height = height |
| self.weight = weight |
| def get_bmi(self): |
| bmi = self.weight / (self.height ** 2) |
| return bmi |
| |
| p = Person(height=1.8,weight=65) |
| |
| print(p.get_bmi()) |
| |
| |
| '''加了property''' |
| class Person(object): |
| def __init__(self, height, weight): |
| '''初始化得到对象的身高体重''' |
| self.height = height |
| self.weight = weight |
| |
| @property |
| def bmi(self): |
| bmi = self.weight / (self.height ** 2) |
| return bmi |
| |
| |
| p = Person(height=1.8, weight=65) |
| |
| print(p.bmi) |
【4】扩展:装饰器@property
的扩展用法@x.setter
,@x.deleter
| '''通过打印上述bmi的类,可以看到他属于property类下的对象了''' |
| print(Person.bmi.__class__) |
| '''方式一:使用装饰器''' |
| class Person(object): |
| def __init__(self, username): |
| '''初始化得到对象的身高体重''' |
| |
| self.__username = username |
| |
| @property |
| def name(self): |
| return self.__username |
| |
| '''使用装饰器的方法限制函数名必须为property装饰的函数名''' |
| @name.setter |
| def name(self, value): |
| |
| self.__username = value |
| |
| @name.deleter |
| def name(self): |
| del self.__username |
| |
| |
| |
| p = Person(username='user') |
| print(p.__dict__) |
| print(p.name) |
| p.name = '001' |
| print(p.name) |
| del p.name |
| print(p.__dict__) |
| '''方式二:使用property()''' |
| class Person(object): |
| def __init__(self, username): |
| '''初始化得到对象的身高体重''' |
| |
| self.__username = username |
| |
| def name(self): |
| return self.__username |
| |
| def name_setter(self, value): |
| self.__username = value |
| |
| def name_deleter(self): |
| del self.__username |
| |
| '''使用property函数时,不限制函数名,按照关键字传参可以不按照顺序,但位置参数顺序不可以乱''' |
| name = property(fget=name, fset=name_setter, fdel=name_deleter) |
| |
| |
| |
| p = Person(username='user') |
| print(p.__dict__) |
| print(p.name) |
| p.name = '001' |
| print(p.name) |
| del p.name |
| print(p.__dict__) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了