封装机制保证了类内部数据结构的完整性,因为使用类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。
一个类实现良好的封装,用户只能借助暴露出来的类方法来访问数据,我们只需要在这些暴露的方法中加入适当的控制逻辑,即可轻松实现用户对类中属性或方法的不合理操作。
对类进行良好的封装,还可以提高代码的复用性。
1. public:公有属性的类变量和类函数,在类的外部、类内部以及子类中,都可以正常访问; 2. private:私有属性的类变量和类函数,只能在本类内部使用,类的外部以及子类都无法使用。
例如,如下程序示范了 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 在底层实现时,将它们的名称都偷偷改成了 "_类名__属性(方法)名" 的格式。
### 用下列方式可以访问到类中的私有属性 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 底层修改类属性或者类方法的名称,以此将它们隐藏起来,只需将它们的名称前添加双下划线(“__”)即可。