面向对象三大特性之封装
封装
封装作为面向对象三大特性中最重要的一个,也是所有使用面向对象编程的程序设计者最喜欢的一个特性,
即:将数据和功能整合到一起。
类本身就是属于封装:
定义一个类,该类中的变量以及方法就只有该类或者其实例化才能调用,这就是封装。当然除此之外还有一些其他的内容。比如:
1.隐藏接口
2.开放接口
单下与双下封装法
1.隐藏接口
对于单下划线开头的属性或者方法来说,Python并不推荐直接使用该属性或方法,但是并不强制被外部调用。
对于双下划线开头的属性或者方法来说,Python根本不希望被外部直接调用,因此外部不能直接调用。
2.开放接口
可以使用
@property
或者某个未定义为隐藏的方法进行调用。因为隐藏接口是对外部隐藏,对内部开放。(即:类的内部方法功能能够去调用
_
开头或者__
开头的属性或方法,但是对于外部来说也就是实例来说这些都是属于不该去被调用或者不能去被调用的)Ps:有的教程中会将此称为私有方法。
class Schoolgirl(object): def __init__(self,name,age): # 注意,以双下划线开头,双下划线结尾的并不属于隐藏接口的范畴!! self._name = name # 对于单下划线开头的属性或者方法来说,Python并不推荐直接使用该属性或方法,但是并不强制被外部调用。 self.__age = age # 对于双下划线开头的属性或者方法来说,Python根本不希望被外部直接调用,因此外部不能直接调用。 def show_msg(self): """这里就相当于开了一个接口""" print("我的名字是:[{0}],我的年龄是:[{1}]".format(self._name,self.__age)) s1 = Schoolgirl("昭儿",18 ) # print(s1._name) # 可以访问该属性,但是并不推荐,这是一种约定 # print(s1.__age) # 直接不让外部访问。 s1.show_msg() # 可以通过文明的方式进行访问 # ==== 执行结果 ==== """ 我的名字是:[昭儿],我的年龄是:[18] """
class Package(object): def __f1(self): print("正在运行f1") def __f2(self): print("正在运行f2") def __f3(self): print("正在运行f3") def interface(self): """由于隐藏是对外部的,故内部可以随意使用或调用,那么interface这个方法也就是属于一个接口方法""" self.__f1() self.__f2() self.__f3() p1 = Package() p1.interface() # ==== 执行结果 ==== """ 正在运行f1 正在运行f2 正在运行f3 """
双下封装法内部原理
Python的
class
机制采用双下划线开头的方式将属性隐藏起来(设置成私有的),但其实这仅仅只是一种变形操作,类中所有双下滑线开头的属性都会在类定义阶段、检测语法时自动变成“
_类名__属性名
”的形式。需要注意的问题:
1.在类外部无法直接访问双下滑线开头的属性,但知道了类名和属性名就可以拼出名字:类名_属性,然后就可以访问了,如
Foo.A__N
,所以说这种操作并没有严格意义上地限制外部访问,仅仅只是一种语法意义上的变形。2.变形操作只在类定义阶段发生一次,在类定义之后的赋值操作,不会变形。
class Schoolgirl(object): def __init__(self,name,age): self._name = name # 对于单下划线开头的属性或者方法来说,Python并不推荐直接使用该属性或方法,但是并不强制被外部调用。 self.__age = age # 对于双下划线开头的属性或者方法来说,Python并不希望被外部直接调用,因此外部不能直接调用。 def show_msg(self): """这里就相当于开了一个接口""" print("我的名字是:[{0}],我的年龄是:[{1}]".format(self._name,self.__age)) s1 = Schoolgirl("昭儿",18 ) s1.show_msg() # ==== 验证:类中所有双下滑线开头的属性都会在类定义阶段、检测语法时自动变成“_类名__属性名”的形式。 ==== print(s1.__dict__) # {'_name': '昭儿', '_Schoolgirl__age': 18} print(s1._Schoolgirl__age) # 18 # ==== 验证:变形操作只在类定义阶段发生一次,在类定义之后的赋值操作,不会变形 ==== s1.__weight = 87 print(s1.__dict__) # {'_name': '昭儿', '_Schoolgirl__age': 18, '__weight': 87} print(s1.__weight) # 87
封装与property
property
本身就是属于封装的另一体现形式。关于property