Python 封装
封装原则是面向对象编程范式的主要支柱之一。Python在实现封装方面采取了不同的方法。
我们知道,类是一个用户定义的对象原型。它定义了一组能够处理数据的数据成员和方法。根据数据封装的原则,描述对象的数据成员对于类外部的环境是隐藏的。它们只能被类内定义的方法处理。另一方面,方法本身是可以从类外部访问的。因此,对象数据被方法称为封装的。这种封装的结果是防止对对象数据的任何不合理访问。
像C ++和Java这样的语言使用访问修饰符来限制对类成员(即变量和方法)的访问。这些语言有关键字public、protected和private来指定访问类型。
如果类成员可以从程序的任何地方访问,则称其为public。私有成员只能从类内部访问。通常,方法被定义为public,实例变量被定义为private。这种私有实例变量和公共方法的安排确保了封装的实现。
与这些语言不同,Python没有提供指定类成员可能具有的访问类型的功能。默认情况下,Python类中的所有变量和方法都是public的,如以下示例所示。
示例1
在这里,我们有一个Employee类,它有实例变量 name 和 age 。这个类的对象具有这两个属性。因为它们是public的,所以可以直接从类外部访问它们。
class Student:
def __init__(self, name="Rajaram", marks=50):
self.name = name
self.marks = marks
s1 = Student()
s2 = Student("Bharat", 25)
print ("Name: {} marks: {}".format(s1.name, s2.marks))
print ("Name: {} marks: {}".format(s2.name, s2.marks))
它将产生以下 输出 −
Name: Rajaram marks: 50
Name: Bharat marks: 25
在上面的例子中,实例变量是在类内部进行初始化的。然而,对于从类外部访问实例变量的值没有限制,这违背了封装原则。
虽然没有关键字来强制可见性,但是Python有一种特殊的命名约定来命名实例变量。在Python中,使用单下划线或双下划线作为变量/方法的前缀,以模拟受保护和私有访问修饰符的行为。
如果一个变量的前缀是双下划线(如 “__age
“),那么实例变量是私有的;类似地,如果变量名的前缀是单下划线(如 “_salary
“)
示例2
让我们修改Student类。添加另一个实例变量salary。将名字设为私有,并将marks设为私有,为它们加上双下划线作为前缀。
class Student:
def __init__(self, name="Rajaram", marks=50):
self.__name = name
self.__marks = marks
def studentdata(self):
print ("Name: {} marks: {}".format(self.__name, self.__marks))
s1 = Student()
s2 = Student("Bharat", 25)
s1.studentdata()
s2.studentdata()
print ("Name: {} marks: {}".format(s1.__name, s2.__marks))
print ("Name: {} marks: {}".format(s2.__name, __s2.marks))
当您运行这段代码时,它将产生以下输出。
Name: Rajaram marks: 50
Name: Bharat marks: 25
Traceback (most recent call last):
File "C:\Python311\hello.py", line 14, in <module>
print ("Name: {} marks: {}".format(s1.__name, s2.__marks))
AttributeError: 'Student' object has no attribute '__name'
上述输出清楚地表明,尽管实例变量名和年龄可以被类内声明的方法(studentdata()方法)访问,但由于双下划线前缀使变量变为私有变量,因此禁止在类外部访问,引发属性错误。
Python并不完全阻止对私有数据的访问。它只是留给程序员的智慧来决定是否编写从类外访问它的代码。您仍然可以通过Python的名称改编技术访问私有成员。
名称改编是将双下划线的成员名更改为以下形式的过程: 对象._class__变量
。如果需要,仍然可以从类外访问它,但应该避免这样做。
在我们的示例中,私有实例变量“__name”通过更改格式为…
obj._class__privatevar
所以,要访问”s1″对象的”__marks
“实例变量的值,将它改为”s1._Student__marks
“。
将上面程序中的print()语句改为 –
print (s1._Student__marks)
现在打印出来的是s1的成绩50。
因此,我们可以得出结论,Python并没有完全按照面向对象编程的理论实现封装。它采用了一种更成熟的方法,通过规定命名约定,并允许程序员在公共范围内使用名称重整来访问私有数据,只有确实需要这样做时才使用。