网站建设公众号开,搜索引擎营销的基本流程,禹城建设局网站,电商网站有什么一、什么是封装
在程序设计中#xff0c;封装#xff08;Encapsulation#xff09;是对具体对象的一种抽象#xff0c;即将某些部分隐藏起来#xff0c;在程序外部看不到#xff0c;其
含义是其他程序无法调用。
要了解封装#xff0c;离不开“私有化”#xff0c;就是…一、什么是封装
在程序设计中封装Encapsulation是对具体对象的一种抽象即将某些部分隐藏起来在程序外部看不到其
含义是其他程序无法调用。
要了解封装离不开“私有化”就是将类或者是函数中的某些属性限制在某个区域之内外部无法调用。
二、为什么要封装
封装数据的主要原因是保护隐私把不想别人知道的东西封装起来
封装方法的主要原因是隔离复杂度比如电视机我们看见的就是一个黑匣子其实里面有很多电器元件对于
用户来说我们不需要清楚里面都有些元件电视机把那些电器元件封装在黑匣子里提供给用户的只是几个按钮接口
通过按钮就能实现对电视机的操作。
提示在编程语言里对外提供的接口接口可理解为了一个入口就是函数称为接口函数这与接口的概念还
不一样接口代表一组接口函数的集合体。
三、封装分为两个层面
封装其实分为两个层面但无论哪种层面的封装都要对外界提供好访问你内部隐藏内容的接口接口可以理解为入
口有了这个入口使用者无需且不能够直接访问到内部隐藏的细节只能走接口并且我们可以在接口的实现上附加更
多的处理逻辑从而严格控制使用者的访问
第一个层面的封装什么都不用做创建类和对象会分别创建二者的名称空间我们只能用类名.或者obj.的方式去
访问里面的名字这本身就是一种封装。
print(m1.brand) #实例化对象m1.
print(motor_vehicle.tag) #类名motor_vehicle.
-------------输出结果--------------
春风
fuel oil
注意对于这一层面的封装隐藏类名.和实例名.就是访问隐藏属性的接口
第二个层面的封装类中把某些属性和方法隐藏起来(或者说定义成私有的)只在类的内部使用、外部无法访问或
者留下少量接口函数供外部访问。
Python中私有化的方法也比较简单即在准备私有化的属性包括方法、数据名字前面加两个下划线即可。
类中所有双下划线开头的名称如__x都会自动变形成_类名__x的形式
class A:
__N0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
def __init__(self):
self.__X10 #变形为self._A__X
def __foo(self): #变形为_A__foo
print(from A)
def bar(self):
self.__foo() #只有在类内部才可以通过__foo的形式访问到.
这种自动变形的特点
1、类中定义的__x只能在内部使用如self.__x引用的就是变形的结果。
2、这种变形其实正是针对外部的变形在外部是无法通过__x这个名字访问到的。
3、在子类定义的__x不会覆盖在父类定义的__x因为子类中变形成了_子类名__x,而父类中变形成了_父
类名__x即双下滑线开头的属性在继承给子类时子类是无法覆盖的。
注意对于这一层面的封装隐藏我们需要在类中定义一个函数接口函数在它内部访问被隐藏的属性然后
外部就可以使用了
这种变形需要注意的问题是
1、这种机制也并没有真正意义上限制我们从外部直接访问属性知道了类名和属性名就可以拼出名字_类名__属
性然后就可以访问了如a._A__N
a A()
print(a._A__N)
print(a._A__X)
print(A._A__N)
--------输出结果--------
0
10
0
2、变形的过程只在类的定义是发生一次,在定义后的赋值操作不会变形
a A() #实例化对象a
print(a.__dict__) #打印变形的内容
a.__Y 20 #新增Y的值此时加__不会变形
print(a.__dict__) #打印变形的内容
---------输出结果----------
{_A__X: 10}
{_A__X: 10, __Y: 20} #发现后面的Y并没有变形
3、在继承中父类如果不想让子类覆盖自己的方法可以将方法定义为私有的
class A: #这是正常情况
def fa(self):
print(from A)
def test(self):
self.fa()
class B(A):
def fa(self):
print(from B)
b B()
b.test()
--------输出结果----------
from B
看一下把fa被定义成私有的情况
class A: #把fa定义成私有的即__fa
def __fa(self): #在定义时就变形为_A__fa
print(from A)
def test(self):
self.__fa() #只会与自己所在的类为准,即调用_A__fa
class B(A):
def __fa(self): #b调用的是test跟这个没关系
print(from B)
b B()
b.test()
-------输出结果---------
from A
四、特性property
1、什么是特性property
property是一种特殊的属性访问它时会执行一段功能函数然后返回值就是一个装饰器
注意被property装饰的属性会优先于对象的属性被使用而被propery装饰的属性,分成三种property、被装饰
的函数名.setter、被装饰的函数名.deleter都是以装饰器的形式。
class room: #定义一个房间的类
def __init__(self,length,width,high):
self.length length #房间的长
self.width width #房间的宽
self.high high #房间的高
property
def area(self): #求房间的平方的功能
return self.length * self.width #房间的面积就是长x宽
property
def perimeter(self): #求房间的周长的功能
return 2 * (self.length self.width) #公式为长 宽x 2
property
def volume(self): #求房间的体积的功能
return self.length * self.width * self.high #公式为长 x 宽 x 高
r1 room(2,3,4) #实例化一个对象r1
print(r1.area,r1.area) #可以像访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(r1.perimeter,r1.perimeter) #同上就不用像调用绑定方法一样还得加括号才能运行
print(r1.volume,r1.volume) #同上就像是把运算过程封装到一个函数内部我们不管过程只要有结果就行
------------输出结果---------------
r1.area 6
r1.perimeter 10
r1.volume 24
注意此时的特性arear、perimeter和volume不能被赋值。
r1.area 8 #为特性area赋值
r1.perimeter 14 #为特性perimeter赋值
r1.volume 24 #为特性volume赋值抛出异常
r1.area 8 #第一个就抛异常了后面的也一样
AttributeError: cant set attribute2、为什么要用property
将一个类的函数定义成特性以后对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后
计算出来的这种特性的使用方式遵循了统一访问的原则。
class people: #定义一个人的类
def __init__(self,name,sex):
self.name name
self.sex sex #p1.sex male,遇到property优先用property
property #查看sex的值
def sex(self):
return self.__sex #返回正真存值的地方
sex.setter #修改sex的值
def sex(self,value):
if not isinstance(value,str): #在设定值之前进行类型检查
raise TypeError(性别必须是字符串类型) #不是str类型时主动抛出异常
self.__sex value #类型正确的时候直接修改__sex的值这是值正真存放的地方
#这里sex前加__,对sex变形隐藏。
sex.deleter #删除sex
def sex(self):
del self.__sex
p1 people(egon,male) #实例化对象p1
print(p1.sex) #查看p1的sex此时要注意self.sex的优先级
p1.sex female #修改sex的值
print(p1.sex) #查看修改后p1的sex
print(p1.__dict__) #查看p1的名称空间此时里面有sex
del p1.sex #删除p1的sex
print(p1.__dict__) #查看p1的名称空间此时发现里面已经没有sex了
-------------------输出结果--------------------
male
female
{name: egon, _people__sex: female}
{name: egon}
python并没有在语法上把它们三个内建到自己的class机制中在C里一般会将所有的所有的数据都设置为私有的
然后提供set和get方法接口去设置和获取在python中通过property方法可以实现。
五、封装与扩展性
封装在于明确区分内外使得类实现者可以修改封装内的东西而不影响外部调用者的代码而外部使用用者只知道一
个接口(函数)只要接口函数名、参数不变使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说
只要接口这个基础约定不变则代码改变不足为虑。
#类的设计者
class room: #定义一个房间的类
def __init__(self,name,owner,length,width,high):
self.name name
self.owner owner
self.__length length #房间的长
self.__width width #房间的宽
self.__high high #房间的高
property
def area(self): #求房间的平方的功能
return self.__length * self.__width #对外提供的接口隐藏了内部的实现细节\
# 此时我们想求的是房间的面积就是长x宽
实例化对象通过接口调用相关属性得到想要的值
#类的使用者
r1 room(客厅,michael,20,30,9) #实例化一个对象r1
print(r1.area) #通过接口使用area使用者得到了客厅的面积
-------------输出结果--------------
600 #得到了客厅的面积
扩展原有的代码使功能增加
#类的设计者轻松的扩展了功能而类的使用者完全不需要改变自己的代码
class room: #定义一个房间的类
def __init__(self,name,owner,length,width,high):
self.name name #房间名
self.owner owner #房子的主人
self.__length length #房间的长
self.__width width #房间的宽
self.__high high #房间的高
property
def area(self): #对外提供的接口隐藏内部实现
return self.__length * self.__width,\
self.__length * self.__width * self.__high #此时我们增加了求体积,
# 内部逻辑变了,只需增加这行代码就能简单实现,而且外部调用感知不到,仍然使
# 用该方法但是功能已经增加了
对于类的使用者仍然在调用area接口的人来说根本无需改动自己的代码就可以用上新功能
#类的使用者
r1 room(客厅,michael,20,30,9) #实例化一个对象r1
print(r1.area) #通过接口使用area使用者得到了客厅的面积
--------------输出结果---------------
(600, 5400) #得到了新增的功能的值