Python封装及实现方法
什么是封装?
- 在设计类时,刻意地将一些属性和方法隐藏在类的内部,这样在使用此类时,将无法直接以“类对象.属性名”(或者“类对象.方法名(参数)”)的形式调用这些属性(或方法),而只能用未隐藏的类方法间接操作这些隐藏的属性和方法。封装绝不是将类中所有的方法都隐藏起来,一定要留一些像键盘、鼠标这样可供外界使用的类方法。
封装的好处是什么?
-
封装机制保证了类内部数据结构的完整性,因为使用类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。
-
一个类实现良好的封装,用户只能借助暴露出来的类方法来访问数据,我们只需要在这些暴露的方法中加入适当的控制逻辑,即可轻松实现用户对类中属性或方法的不合理操作。
-
对类进行良好的封装,还可以提高代码的复用性。
Python 类如何封装?
- Python 类中的变量和函数,不是公有的(类似 public 属性),就是私有的(类似 private),这 2 种属性的区别如下:
1. public:公有属性的类变量和类函数,在类的外部、类内部以及子类中,都可以正常访问;
2. private:私有属性的类变量和类函数,只能在本类内部使用,类的外部以及子类都无法使用。
- 默认情况下,Python 类中的变量和方法都是公有(public)的,它们的名称前都没有下划线 “_”,如果类中的变量和函数,其名称以双下划线“__”开头,则该变量(函数)为私有变量(私有函数),其属性等同于 private。
- 除此之外,还可以定义以单下划线“_”开头的类属性或者类方法(例如 _name、_display(self)),这种类属性和类方法通常被视为私有属性和私有方法,虽然它们也能通过类对象正常访问,但这是一种约定俗称的用法,初学者一定要遵守。
例如,如下程序示范了 Python 的封装机制:
class Students:
def set_name(self, name):
if len(name) < 3:
raise ValueError('名称长度必须大于3!')
self.__name = name
def get_name(self):
return self.__name
name = property(get_name, set_name) # 为 name 配置 setter 和 getter 方法
def set_add(self, add):
if add.startswith("http://"):
self.__add = add
else:
raise ValueError('地址必须以 http:// 开头')
def get_add(self):
return self.__add
add = property(get_add, set_add) # 为 add 配置 setter 和 getter 方法
# 定义个私有方法
def __display(self):
print(self.__name, self.__add)
student = Students()
student.name = "大切切"
student.add = "http://www.cnblogs.com/bigcarcar"
print(student.name)
print(student.add)
###运行结果
大切切
http://www.cnblogs.com/bigcarcar
-
上面程序中,Students 将 name 和 add 属性都隐藏了起来,但同时也提供了可操作它们的“窗口”,也就是各自的 setter 和 getter 方法,这些方法都是公有(public)的。
-
通过此程序的运行逻辑不难看出,通过对 Students 类进行良好的封装,使得用户仅能通过暴露的 setter() 和 getter() 方法操作 name 和 add 属性,而通过对 setname() 和 setadd() 方法进行适当的设计,可以避免用户对类中属性的不合理操作,从而提高了类的可维护性和安全性。
其中__display()为该类私有(private)方法,且该类没有提供操作该私有方法的“窗口”,因此我们无法在类的外部使用它。如下调用 __display() 方法是不可行的
student.__display() # 发起调用
### 返回报错
Traceback (most recent call last):
File "tests.py", line 68, in <module>
student.__display()
AttributeError: 'Students' object has no attribute '__display'
封装原理详解
- 事实上,Python 封装特性的实现纯属“投机取巧”,之所以类对象无法直接调用以双下划线开头命名的类属性和类方法,是因为其底层实现时,Python 偷偷改变了它们的名称。
事实上,对于以双下划线开头命名的类属性或类方法,Python 在底层实现时,将它们的名称都偷偷改成了 "_类名__属性(方法)名" 的格式。
### 用下列方式可以访问到类中的私有属性
student._Students__display()
print(student._Students__name)
print(student._Students__add)
### 运行结果:
大切切 http://www.cnblogs.com/bigcarcar
大切切
http://www.cnblogs.com/bigcarcar
甚至于,我们还可以通过这种方式修改 student 对象的私有属性,例如:
### 修改对象私有属性
student._Students__name = '麻花藤'
student._Students__add = 'www.qq.com'
print(student._Students__name)
print(student._Students__add)
### 运行结果:
麻花藤
www.qq.com
总结
Python 类中所有的属性和方法,都是公有(public)属性,如果希望 Python 底层修改类属性或者类方法的名称,以此将它们隐藏起来,只需将它们的名称前添加双下划线(“__”)即可。