python 封装、绑定
python 封装、绑定

面向对象共有三大特性:封装、继承、多态,这篇文章主要介绍一下类的封装,以及类的绑定。
封装:意思就是整合代码,将数据和功能整合到一起,起到规范代码的作用,更好的组织了项目的整体结构,减少了代码的冗余度,提升了可扩展性
类的封装主要分为数据封装、方法封装
1、数据、方法的封装
示例如下:
# 未封装前
name = 'HammerZe'
age = 18
gender = 'male'
print(f' name:{name}\n',
f'age{age}\n',
f'gender:{gender}')
# 结果
name:HammerZe
age:18
gender:male
这样看起来数据完全暴露出来,一个人的信息如此,如果多人的信息这样统计起来或者修改起来岂不是很麻烦?规定每个人的信息格式,整合起来首先比较方便,只需几行代码就可以显示一个人的全部信息
# 数据、方法封装
class Self_Info():
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
# 方法/功能的封装
def view_info(self):
print(f" name:{self.name}\n",
f"age:{self.age}\n",
f"gender:{self.gender}")
obj = Self_Info('HammerZe',18,'male')
obj.view_info()
# 结果
name:HammerZe
age:18
gender:male
看似封装后的代码多了很多,如果下次需要格式化输出其他人的信息,只需按照格式传参即可,不需要重新定义,重新写,这就规范了数据的一致性,比较好管理,上篇中介绍到类的增删查改,这样个人信息是不是也更好修改,不需要“牵一发而动全身”
2、隐藏属性
Python中,类内的属性是可以私有化的,就是把数据隐藏起来,对类外隐藏,类内可继续操作数据或方法。
私有属性格式:__属性名(数据/方法)
示例如下:
'''未私有前'''
class Info():
address = 'shanghai'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def get_info(self):
print(f" name:{self.name}\n",
f"age:{self.age}\n",
f"gender:{self.gender}\n",
f"address:{self.address}")
obj = Info('HammerZe',18,'male')
obj.get_info()
# 结果
name:HammerZe
age:18
gender:male
address:shanghai
'''如果我们不想对类外开放个人地址,可以私有化'''
# 属性私有
__address = 'shanghai' # 只需在数据名前加__,如果继续获取会报错
# 结果>>>AttributeError: 'Info' object has no attribute 'address'
# 属性私有
class Info():
__address = 'shanghai' #底层:_Info__address
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def get_info(self):
print(f" name:{self.name}\n",
f"age:{self.age}\n",
f"gender:{self.gender}\n",
f"address:{self.__address}")
'''获取地址前加__'''
obj = Info('HammerZe',18,'male')
obj.get_info()
# 结果
name:HammerZe
age:18
gender:male
address:shanghai
'''私有了就不能获取到了吗?这个只是更改了数据的格式,如果想访问到可以通过获取数据格式,访问'''
# 通过__dict__查看名称空间,发现__address格式变为_Info__address
print(Info.__dict__)
# 所以在类外通过获取到数据格式也是可以获取到的
print(obj._Info__address) # shanghai
- 注意!数据和方法的私有格式一样,知道底层的格式也是可以调用/获取到方法内和数据的信息,互联网没有绝对的安全
3、开放接口
- 类的私有原则是对外私有,但是在类内可以修改和继续使用,定义属性就是为了使用
计算器有很多种功能,但是我们在使用的时候只需输入数,通过计算就能得到结果,那么底层的数学原理我们不需要知道,只求结果即可,那么很多功能就可以私有,只暴露给用户结果!
# 属性私有
'''以幂运算为例'''
class Calculator():
def __init__(self):
self.num1 = int(input('请输入底数>>>:'))
print(f'您输入的底数为{self.num1}')
# 幂运算
def __pow(self,n):
return self.num1**n
def get_res(self):
get_n = int(input('输入要计算幂运算的次方数>>>:'))
res = self.__pow(get_n)
print(f'幂运算结果为{res}')
num = Calculator()
num.get_res()
# 结果
请输入底数>>>:22
您输入的底数为22
输入要计算幂运算的次方数>>>:1
幂运算结果为22
'''这样我们只需要输入数,幂运算的功能可以隐藏起来,只暴露给用户功能接口,返回结果'''
4、绑定方法
1、对象的绑定
class Info():
def __init__(self,name,age):
self.name = name
self.age = age
'''绑定给对象的方法,对象来调用,会把自己当成第一个参数传到函数里面self'''
def get_info(self):
print(f'姓名:{self.name}|年龄:{self.age}')
obj = Info('HammerZe',18)
obj.get_info()
# 结果
# 姓名:HammerZe|年龄:18
2、类的绑定(classmethod)
class Student():
def __init__(self,name,age):
self.name = name
self.age = age
# @classmethod
# def change(self):
# obj = self.__class__('HammerZe', 18)
# return obj
'''上面注释掉这种方法等价与下面的方法'''
@classmethod
def change(cls):
obj = cls('HammerZe', 18)
return obj
# 生成对象
stu = Student('ly',18)
print(stu.__dict__)
print(id(stu))
# 生成对象,再用新对象接收
obj = stu.change()
print(obj.__dict__)
print(id(obj))
'''stu.__class__.fun() 等价 Student.fun()'''
# 类调用
obj1 = Student.change()
print(obj1.__dict__)
print(id(obj1))
3、非绑定方法(staticmethod)
''' 统计调用类,产生了多少个对象'''
class Count_obj():
# 定义count
count = 0
def __init__(self):
Count_obj.count += 1
# 静态方法/非绑定方法:既不绑定给类,也不绑定给对象
@staticmethod
def count_info():
print(f'产生了{Count_obj.count}个对象')
# 调用类产生对象
obj = Count_obj()
obj1 = Count_obj()
obj2 = Count_obj()
obj3 = Count_obj()
obj4 = Count_obj()
# 查看生成了多少个对象
Count_obj.count_info()
'''注意,修改的是类体内的count,如果self.count只能在对象的名称空间中产生一次count,达不到统计的效果'''
4、property()函数及property装饰器
1、 property() 函数
格式:property(fget=None, fset=None, fdel=None, doc=None)
- fget:获取属性值的方法
- fset:设置属性值的方法
- fdel:删除属性值的方法
- doc:属性描述信息
示例如下:
class Student:
def __init__(self):
self._age = None
def get_age(self):
print('查看属性时执行的代码')
return self._age
def set_age(self, age):
print('设置属性时执行的代码')
self._age = age
def del_age(self):
print('删除属性时执行的代码')
del self._age
age = property(get_age, set_age, del_age, '学生年龄')
student = Student()
# 注意要用 类名.属性.__doc__ 的形式查看属性的文档字符串
print('查看属性的文档字符串:' + Student.age.__doc__)
"""
查看属性的文档字符串:学生年龄
"""
# 设置属性
student.age = 18
"""
设置属性时执行的代码
"""
# 查看属性
print('学生年龄为:' + str(student.age))
"""
获取属性时执行的代码
学生年龄为:18
"""
# 删除属性
del student.age
"""
删除属性时执行的代码
"""
print(student.__dict__) # {}
property装饰器
property装饰器可以将类中的函数‘伪装成’对象的数据属性,对象在访问该特殊属性时会触发功能的执行,然后将返回值作为本次的访问结果
@property语法糖提供了比property()函数更简洁直观的写法。被
@property装饰的方法是获取属性值的方法,被装饰方法的名字会被用做属性名。被
@属性名.setter装饰的方法是设置属性值的方法。被
@属性名.deleter装饰的方法是删除属性值的方法。
以下示例代码与使用
property()函数版本的代码等价:
class Student:
def __init__(self):
self._age = None
@property
def age(self):
print('查看属性时执行的代码')
return self._age
@age.setter
def age(self, age):
print('设置属性时执行的代码')
self._age = age
@age.deleter
def age(self):
print('删除属性时执行的代码')
del self._age
student = Student()
# 设置属性
student.age = 18
"""
设置属性时执行的代码
"""
# 获取属性
print('学生年龄为:' + str(student.age))
"""
查看属性时执行的代码
学生年龄为:18
"""
# 删除属性
del student.age
"""
删除属性时执行的代码
"""
3、注意!
- 可以省略设置属性值的方法,此时该属性变成只读属性。如果此时仍然设置属性,会抛出异常 AttributeError: can't set attribute。
- 如果报错 RecursionError: maximum recursion depth exceeded while calling a Python object,很可能是对象属性名和 @property 装饰的方法名重名了,一般会在对象属性名前加一个下划线 _ 避免重名,并且表明这是一个受保护的属性。
property参考:
【待续】

python 封装、绑定的更多相关文章
- python 延迟绑定
def multipliers(n): funcs = [] for i in range(n): def f(x): return x * i funcs.append(f) return func ...
- python封装configparser模块获取conf.ini值(优化版)
昨天晚上封装了configparser模块,是根据keyname获取的value.python封装configparser模块获取conf.ini值 我原本是想通过config.ini文件中的sect ...
- 使用boost.python封装C++库
使用boost.python封装C++库 C++以高性能著称,但是编写较为复杂.而简洁是Python的强项.如果能珠联璧合,就能发挥两家之长.本文尝试用boost库的python模块封装C++ 前期准 ...
- 【AMAD】python-magic -- libmagic的python封装
简介 动机 作用 用法 个人评分 简介 libmagic的python封装 动机 封装libmagic,使用python代码获取文件类型. 作用 libmagic通过文件头部,来确定文件的类型. 用法 ...
- python 封装底层实现原理
事实上,python封装特性的实现纯属"投机取巧",之所以类对象无法直接调用私有方法和属性,是因为底层实现时,python偷偷改变了它们的名称. python在底层实现时,将它们的 ...
- [转载]Python方法绑定——Unbound/Bound method object的一些梳理
本篇主要总结Python中绑定方法对象(Bound method object)和未绑定方法对象(Unboud method object)的区别和联系.主要目的是分清楚这两个极容易混淆的概念,顺便将 ...
- Python封装应用程序的最佳项目结构是什么?
Python封装应用程序的最佳项目结构是什么? 转载来源于stackoverflow:https://stackoverflow.com/questions/193161/what-is-the-be ...
- python 封装,隐藏属性,绑定方法classmethod和staticmethod
[封装] 隐藏对象的属性和实现细节,仅对外提供公共访问方式. [好处] 1. 将变化隔离: 2. 便于使用: 3. 提高复用性: 4. 提高安全性: [封装原则] 1. 将不需要对外提供的内容都隐藏起 ...
- Python封装
什么是封装 在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其 含义是其他程序无法调用. 要了解封装,离不开“私有化”,就是将类或者是函 ...
随机推荐
- RocketMQ源码详解 | Producer篇 · 其一:Start,然后 Send 一条消息
概述 DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name"); ...
- 2021.10.27考试总结[冲刺NOIP模拟17]
T1 宝藏 发现每个数成为中位数的长度是关于权值单调的.线段树二分判断是否合法,单调指针扫即可. 考场上写了二分,平添\(\log\). \(code:\) T1 #include<bits/s ...
- c#复制数组的多种方法
方法一:使用for循环 int []pins = {9,3,7,2} int []copy = new int[pins.length]; for(int i =0;i!=copy.length;i+ ...
- Maven打包web项目报错:webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update)
问题描述 使用Maven打包项目的时候,出现错误: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing ...
- uni-app map组件关于marker标记点动态设置的问题
marker是Array类型,赋值的时候只能对整个数组进行更改赋值,不能只改变内部的对象,亲测Vue.$set()也不行 this.marker = [ { latitude: 39.90, long ...
- SqlServer修改某个字段的默认值时的操作步骤
sqlserver有时候需要修改一个字段的默认值,却发现修改(update)不了,也删除(delete)不了,排查发现,需要先删除原有的默认值约束,才行:步骤如下1.2.3.若原来这个字段就没有默认值 ...
- 聊一聊声明式接口调用与Nacos的结合使用
背景 对于公司内部的 API 接口,在引入注册中心之后,免不了会用上服务发现这个东西. 现在比较流行的接口调用方式应该是基于声明式接口的调用,它使得开发变得更加简化和快捷. .NET 在声明式接口调用 ...
- windows桌面图标不显示,左右键无法使用的解决方法
问题描述: 日常使用软件中,一返回桌面,桌面图标全部不显示,点击鼠标的左键,右键毫无反应 解决方法: 1. Ctrl+Shift+Esc呼出软仵管理器 2. 右键windows资管理器,点击属性 配图 ...
- 痞子衡嵌入式:再测i.MXRT1060,1170上的普通GPIO与高速GPIO极限翻转频率
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1060/1170上的普通GPIO与高速GPIO极限翻转频率. 按照上一篇文章 <实测i.MXRT1010上的普通GP ...
- [atAGC022D]Shopping
称0到$L$的方向为左,同时为了方便,可以假设$0<t_{i}\le 2L$ 当我们确定是进入店中的方向,根据这个店的位置以及购物时间,不难确定出来时火车经过0或$L$的次数,由于$0<t ...