面向对象编程的一个关键部分是封装,它涉及将相关的变量和函数打包到一个简单易用的对象中 - 一个类的实例。
一个相关的概念是数据隐藏,它指出一个类的实现细节应该被隐藏,并且为那些想要使用这个类的用户提供一个干净的标准接口。
在其他编程语言中,这通常使用私有方法和属性来完成,这些私有方法和属性阻止对类中某些方法和属性被外部访问。
Python 略有不同。没有对任何一个阶级的部分进行任意的限制。因此,没有办法强制一个方法或属性是严格私密的。
但是,有些方法可以阻止人们访问某个类的某些部分。
弱的私有方法和属性在开头只有一个下划线。
这表示它们是私有的,不应该被外部代码使用。但是,它大多只是一个约定,并不会阻止外部代码访问它们。
它唯一的实际效果是 from 模块名 import * 不会导入以单个下划线开头的变量。
例如:
class Queue:
def __init__(self, contents):
self._hiddenlist = list(contents)
def push(self, value):
self._hiddenlist.insert(0, value)
def pop(self):
return self._hiddenlist.pop(-1)
def __repr__(self):
return "Queue({})".format(self._hiddenlist)
queue = Queue([1, 2, 3])
print(queue)
queue.push(0)
print(queue)
queue.pop()
print(queue)
print(queue._hiddenlist)
======
结果:
Queue([1, 2, 3])
Queue([0, 1, 2, 3])
Queue([0, 1, 2])
[0, 1, 2]
在上面的代码中,_hiddenlist 属性被标记为私有的,但仍然可以在外部代码中访问。
repr 魔术方法用于实例的字符串表示。
强私有方法和属性在名称的开始处有一个双下划线。这导致他们的名字错位,这意味着他们不能从类外访问。
这样做的目的不是确保它们保持私有,而是为了避免错误,如果存在具有相同名称的方法或属性的子类时。
名称 错位 方法仍然可以在外部访问,但是以不同的名称访问。 Spam 类的 __private 方法可以通过 _Spam__private 方法外部访问。
例如:
class Spam:
__egg = 7
def print_egg(self):
print(self.__egg)
s = Spam()
s.print_egg()
print(s._Spam__egg)
print(s.__egg)
======
结果:
7
7
AttributeError: 'Spam' object has no attribute '__egg'
基本上,Python 通过内部更改名称来包含类名来保护这些成员。