python的三大特性之封装

封装

隐藏对象的某些属性和实现的细节,仅仅只对外提供公共访问的方式。将函数和属性装到了一个非全局的命名空间。

封装的好处
(1)将变化隔离

(2)便于使用

(3)提高复用性

(4)提高安全性

封装原则

(1)将不需要对外提供的内容全部都隐藏起来

(2)吧属性都隐藏,提供公共方法对其访问

私有变量和私有方法

私有变量:不能在类的外面去引用它。
它依然存在于__dict__中,我们仍然可以调用到。只是python对其的名字进行了修改: _类名__名字。但是在类的外部调用 :需要“_类名__名字”去使用,在类的内部可以正常的使用名字

在python中定义一个私有的名字 :使用两条下划线开头的方式来定义变量名称 __N = ‘aaa’

class Student:
    __id = 0   #变成了私有的静态变量类的数据属性就应该是
               # 共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self, name, age):
        self.name = name  #变形为self._Student__name ,私有属性
        self.age = age    #变形为self._Student__age ,私有属性
    def func(self): 
         print(Student.__id) #在类的内部使用正常
s = Student('hh', 18) 
s.func() 
print(Student.__id) # 在类的外部直接使用 报错

print(Student._Student__id) #不报错

由此,私有变量只能在类的内部访问的到,外部不能访问,但是,由于它是一个变形的方式。其实可以通过变形以后的方式进行访问,但严格意义上来讲,我们不能通过它来访问,这时只有我们程序员知道就可以了

这种自动变形的特点:

1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

变形需要注意的问题是:

1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形

私有方法

私有方法的定义和私有变量一样,只需要在前面加上双下划线,就是标志着私有方法

class Student:
    def func(self):
        print("我是一个好学生")  # 在类的内部使用正常
    def __ADCa(self):
        print("我喜欢喝ADCa")
s = Student()
s.func()               #普通方法调用
s._Student__ADCa()          #私有方法调用
s.__ADCa                       #这样调用,直接报错

在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

#正常情况,方法都是普通方法

class Dad:
    def dear(self):
        print('from Dad')
    def father(self):
        self.dear()
 
class Son(Dad):
    def dear(self):
        print('from Son')
 
s = Son()
s.father()
 
#当某一个方法是私有的时候,子类就不能继承父类的私有方法了
class Dad:
    def dear(self):
        print('from Dad')
    def __father(self):
        self.dear()
 
class Son(Dad):
    def dear(self):
        print('from Son')
 
s = Son()
s.father()

总之,在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字之前加上__

私有的名字,在类内使用的时候,就是会变形成_该类名__方法名。下面这个例子:

以此为例 :没有双下换线会先找E中的func,但是有了双下划线,会在调用这个名字的类D中直接找_D__func

class D:
    def __init__(self):
        self.__func()
    def __func(self):
        print('in D')
 
class E(D):
    def __func(self):
        print('in E')
e = E()   #结果:<em id="__mceDel">in D</em><em id="__mceDel" style="font-size: 1.5em; background-color: #ffffff; font-family: "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif">  </em>

封装与扩展性

封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码

class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,<br>                           #只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high   #对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能

猜你喜欢

转载自blog.csdn.net/qq_38362416/article/details/83959955