Python 简明教程

Python - Encapsulation

unittest 是将属性和方法捆绑在单个单元内的过程。它是 Encapsulation 范例基于的主要支柱之一。

Encapsulation is the process of bundling attributes and methods within a single unit. It is one of the main pillars on which the object-oriented programming paradigm is based.

我们知道,类是对象的由用户定义的原型。它定义了一组数据成员和 object-oriented programming ,能够处理数据。

We know that a class is a user-defined prototype for an object. It defines a set of data members and methods, capable of processing the data.

根据数据封装原则,描述对象的成员数据对于类的外部环境而言是隐藏的。只有通过同一类中的方法才能访问它们。另一方面,方法本身可以从类上下文外部访问。因此,对象数据据说是由方法封装的。通过这种方式,封装可以防止直接访问对象数据。

According to the principle of data encapsulation, the data members that describe an object are hidden from the environment external to the class. They can only be accessed through the methods within the same class. Methods themselves on the other hand are accessible from outside class context. Hence, object data is said to be encapsulated by the methods. In this way, encapsulation prevents direct access to the object data.

Implementing Encapsulation in Python

诸如 methodsC++ 的语言使用 Java 来限制对成员的访问(即,变量和方法)。这些语言有关键字 public、protected 和 private 来指定访问类型。

Languages such as C++ and Java use access modifiers to restrict access to class members (i.e., variables and methods). These languages have keywords public, protected, and private to specify the type of access.

如果可以从程序的任何位置访问它,则称成员是公共的。私有成员只能从类内访问。通常,方法被定义为公共的,实例变量是私有的。私有实例变量和公共方法的这种安排确保实现 access modifiers

A class member is said to be public if it can be accessed from anywhere in the program. Private members are allowed to be accessed from within the class only. Usually, methods are defined as public, and instance variables are private. This arrangement of private instance variables and public methods ensures the implementation of encapsulation.

与这些语言不同, encapsulation 没有任何条款来指定类成员可能具有的访问类型。默认情况下,Python 类中的所有变量和方法都是公开的,如下面的示例所示。

Unlike these languages, Python has no provision to specify the type of access that a class member may have. By default, all the variables and methods in a Python class are public, as demonstrated by the following example.

Example 1

在这里,我们有一个包含实例变量 Pythonname 的 Employee 类。此类的对象具有这两个 age 。它们可以直接从类外部访问,因为它们是公共的。

Here, we have an Employee class with instance variables, name and age. An object of this class has these two attributes. They can be directly accessed from outside the class, because they are 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))

它将生成以下 output

It will produce the following output

Name: Rajaram marks: 50
Name: Bharat marks: 25

在上面的示例中,实例变量在类内初始化。但是,从类外部访问实例变量值没有限制,这违背了封装原则。

In the above example, the instance variables are initialized inside the class. However, there is no restriction on accessing the value of instance variables from outside the class, which is against the principle of encapsulation.

尽管没有用于强制可见性的关键字,但 Python 有以特殊方式命名实例变量的约定。在 Python 中,使用单下划线或双下划线作为变量/方法名的前缀来模拟受保护和私有访问修饰符的行为。

Although there are no keywords to enforce visibility, Python has a convention of naming the instance variables in a peculiar way. In Python, prefixing name of a variable/method with a single or double underscore to emulate the behavior of protected and private access modifiers.

如果某个变量的前缀为单个双下划线(如“ __age ”),则该实例变量为私有变量,类似地,如果某个变量名的前缀为单个下划线(如“ _salary ”)

If a variable is prefixed by a single double underscore (such as "__age"), the instance variable is private, similarly if a variable name is prefixed with a single underscore (such as "_salary")

Example 2

让我们修改 Student 类。添加另一个实例变量salary。通过给 name 和 marks 加上前缀双下划线,将它们变为私有。

Let us modify the Student class. Add another instance variable salary. Make name private and marks as private by prefixing double underscores to them.

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))

当您运行此代码时,它将生成以下 output

When you run this code, it will produce the following output

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'

上述输出明确指出了实例变量 name 和 age 可由类内声明的方法(studentdata() 方法)访问,但双下划线前缀使变量为私有变量,因此,限制了在类外部访问这些变量,这会引发属性错误。

The above output makes it clear that the instance variables name and age, can be accessed by a method declared inside the class (the studentdata() method), but the double underscores prefix makes the variables private, and hence, accessing them outside the class is restricted which raises Attribute error.

What is Name Mangling?

Python 并没有完全阻止对私有数据的访问。它只是将此操作委托给编程人员的智慧,而不是编写从类外部访问这些变量的任何代码。你仍可以通过 Python 的名称混淆技术来访问私有成员。

Python doesn’t block access to private data entirely. It just leaves it to the wisdom of the programmer, not to write any code that accesses it from outside the class. You can still access the private members by Python’s name mangling technique.

名称混淆是将双下划线成员的名称更改为 object._class__variable 格式的过程。如果需要,仍然可以从类外访问它,但应该避免此做法。

Name mangling is the process of changing name of a member with double underscore to the form object._class__variable. If so required, it can still be accessed from outside the class, but the practice should be refrained.

在我们的示例中,私有实例变量 "__name" 被改写为格式以得到破坏

In our example, the private instance variable "__name" is mangled by changing it to the format

obj._class__privatevar

因此,要访问“s1”对象的“_marks”实例变量的值,请将其更改为“s1._Student_marks”。

So, to access the value of "_marks" instance variable of "s1" object, change it to "s1._Student_marks".

将上面程序中的 print() 语句更改为 −

Change the print() statement in the above program to −

print (s1._Student__marks)

它现在打印 s1 的分数 50。

It now prints 50, the marks of s1.

因此,我们可以得出结论,Python 并非完全按照面向对象编程的理论来实现封装。它通过规定一个命名约定并允许编程人员在确实需要在 public 范围内访问私有数据时使用名称混淆,采用了更加成熟的做法。

Hence, we can conclude that Python doesn’t implement encapsulation exactly as per the theory of object-oriented programming. It adapts a more mature approach towards it by prescribing a name convention and letting the programmer use name mangling if it is really required to have access to private data in the public scope.