发布于2020-03-07 19:01 阅读(1968) 评论(0) 点赞(8) 收藏(3)
例子:手机拨打电话,背后的实现是一个很复杂的流程:
1、手机内部功能实现
2、信号与基站进行交互
3、手机对收到的信号进行解码
4、调用手机听筒,将收到的信号实时解码并转化为音频,实现通话。
但是在实际使用中,使用者只需要输入号码拨打电话就可完成通话。
这就是面对对象封装的概念。所以封装的一大特点:就是将复杂的信息、流程给包起来,内部处理,让使用者只需要通过简单的操作步骤,就能实现。 参考:(https://segmentfault.com/a/1190000018963865?utm_source=tag-newest)
'''
1.封装:类就是个麻袋,
2.定义私有的,只在类内部使用,外部无法访问(_,__)
3.明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个访问接口给
外部使用。
'''
class People:
# __ :双下划线,这就是在类中封装的语法
__region = "武汉" # _ People__region 实际发生了变形
def __init__(self, name, age):
self.__name = name
self.age = age
def print_info(self):
print('姓名:%s,年龄:%s,地区:%s'%(self.__name,self.age,self.__region))
obj = People('金鞍少年', 18) # 实例化对象并传入参数
print(obj.age) # 结果-- 18
obj.print_info() # 结果-- 姓名:金鞍少年,年龄:18,地区:武汉
print(obj.__region) # 报错:AttributeError: 'People' object has no attribute '__region',证明__region被私有化封装了
print(People.__dict__) # 查看类的属性和方法
# {'__module__': '__main__', '_People__region': '武汉', '__init__': <function People.__init__ at 0x000001541032C160>, 'print_info': <function People.print_info at 0x000001541032C310>, '_People__FindName': <function People.__FindName at 0x000001541032C3A0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
# 通过分析知道,在类中__region,是以_People__region存储的
print(obj._People__region) # 结果 :武汉
这种自动变形的特点,就是封装:
class Foo:
__N = 1 # 数据(属性)的封装
def __info(self): # 方法封装
print(self.__N)
def print_info(self):
self.__info() # 内部调用封装方法
obj = Foo()
obj.print_info() # 结果 1
obj._Foo__info() # 通过调用变形后的方法名进行调用
Foo.__M = 10 # 类定义之后,外部调用,语法不会发生变形。
print(Foo.__M) # 结果 10
封装在某种意义上就是简单的隐藏:
1,这种语法变形机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__方法,然后就可以访问了,如 obj._Foo__info()
2.变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形 ,如:Foo.__M = 10
虽说封装只是一个语法变形机制的实现,但是其好处有好几点:
主要原因是:保护私隐,明确区分内外。将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。
class people:
def __init__(self,name,age):
self.__name=name
self.__age=age
def print_info(self):
print('姓名:%s, 年龄:%s' %(self.__name,self.__age))
def set_info(self, name, age):
if not isinstance(name, str):
raise TypeError('姓名必须是字符串类型')
if not isinstance(age,int):
raise TypeError('年龄必须是整型')
self.__name = name
self.__age = age
obj = people('jasn',18)
obj.print_info() #结果为:姓名:jasn, 年龄:18
obj.set_info('金鞍少年', 19) # 对修改内容进行限制,规避掉sql注入的可能
obj.print_info() # 结果为:姓名:金鞍少年, 年龄:19
文章开头就讲到封装的一大特点:就是将复杂的信息、流程给包起来,内部处理,让使用者只需要通过简单的操作步骤,就能实现。
#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做隔离了复杂度,同时也提升了安全性
class ATM:
def __card(self):
print('插卡')
def __auth(self):
print('用户认证')
def __input(self):
print('输入取款金额')
def __print_bill(self):
print('打印账单')
def __take_money(self):
print('取款')
def withdraw(self):
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()
a=ATM()
a.withdraw()
Python内置的@property装饰器就是负责把一个方法变成属性
案例一
'''
BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
'''
class People:
def __init__(self, name, height, weight):
self.__name = name
self.__height = height//10
self.__weight = weight
@property
def bmi(self):
BMI = self.__weight / (self.__height ** 2)
return '{:.2f}%' .format(BMI * 100)
obj = People('金鞍少年', 179, 67)
print(obj.bmi)
案例二
# 我们知道一个人年龄必须是整数,而且是有范围限制的。
class People:
def __init__(self,name, age):
self.name = name
self.__age = age
@property # 负责查询
def age(self):
return self.__age
@age.setter # 对修改年龄加以限制
def age(self, value):
if not isinstance(value, int): # 在设定值之前进行类型检查,增加限制的扩展性
raise TypeError('年龄必须为整型!')
if value < 0 or value > 120:
raise TypeError('年龄超出范围!')
self.__age = value
@age.deleter # 删除属性接口
def age(self):
del self.__age # del self.age
obj = People('jasn', 18)
print(obj.age)
obj.age = 99 # 触发age.setter方法
print(obj.age)
del obj.age
print(obj.age) # 删除成功就报错,提示没有
'''
@property的实现比较复杂,我们先考察如何使用。把一个age方法变成属性,只需要加上@property就可以了,
此时,@property本身又创建了另一个装饰器@age.setter,负责把一个age方法变成属性赋值,
于是,我们就拥有一个可控的属性操作来限制age取值范围。
'''
被 property 装饰的属性会优先于对象的属性被使用(找到)
而被 property装饰的属性,分成三种
property 查询
age.setter 赋值,修改 age是方法名
age.deleter 删除
如果对象要修改数据属性的时候,在没有 property 的情况下,可以随便改,但是加了之后就有一个可控的属性操作来限制age取值范围。
作者:我Lovepython
链接:https://www.pythonheidong.com/blog/article/246886/0065f277113bb42a910d/
来源:python黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!