Python面向对象编程第08篇 私有变量

Posted 不剪发的Tony老师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python面向对象编程第08篇 私有变量相关的知识,希望对你有一定的参考价值。

本篇我们介绍封装(encapsulation)的概念,以及如何在 Python 中利用私有属性实现封装。

封装的概念

面向对象编程包含四个基本的概念:抽象、封装、继承以及多态。封装是指将数据和功能包装在对象中,通过封装可以对外隐藏对象的内部状态。封装因此也被称为信息隐藏。

类就是封装的一个示例,它将数据和方法打包成一个单元。同时类还通过方法提供了属性的访问。

信息隐藏的思想就是如果你有一个外部不可见的属性,你可以控制它的访问,确保对象总是处于有效状态。

下面我们通过一个示例来进一步理解封装的概念。

封装的示例

以下示例定义了一个 Counter 类:

class Counter:
    def __init__(self):
        self.current = 0

    def increment(self):
        self.current += 1

    def value(self):
        return self.current

    def reset(self):
        self.current = 0

Counter 类拥有一个属性 current,它的默认值为 0。另外 Counter 类包含三个方法:

  • increment() 将属性 current 的值加一。
  • value() 返回属性 current 的当前值。
  • reset() 将属性 current 的值设置为 0。

以下示例创建了一个新的 Counter 类实例,调用三次 increment() 方法,然后打印 counter 变量的当前值:

counter = Counter()


counter.increment()
counter.increment()
counter.increment()

print(counter.value())

输出结果如下:

3

程序工作正常,但是还有一个问题。我们仍然可以从 Counter 类的外部访问 current 属性并修改它的值。例如:

counter = Counter()

counter.increment()
counter.increment()
counter.current = -999

print(counter.value())

输出结果如下:

-999

在以上示例中,我们创建了一个 Counter 类的实例,调用两次 ncrement() 方法,然后将 current 属性的值设置为一个无效的数值 -999。

那么如何阻止代码从 Counter 类的外部修改 current 属性呢?为此我们需要使用私有属性。

私有属性

私有属性只能从类的方法中访问。也就是说,我们无法从类的外部访问私有属性。

不过,Python 没有提供私有属性的功能。也就是说,任何属性都可以从类的外部访问。

按照惯例,我们可以在变量名前加上一个下划线(_)表示私有属性:

_attribute

以上语法表示 _attribute 不应该直接访问,而且将来在实现上可能会有重大变化。

以下示例重新定义了 Counter 类,使用惯例将 current 变量修改为私有属性:

class Counter:
    def __init__(self):
        self._current = 0

    def increment(self):
        self._current += 1

    def value(self):
        return self._current

    def reset(self):
        self._current = 0

名称改写

如果在属性名前面加上双下划线前缀:

__attribute

Python 会自动将 __attribute 属性名修改为以下名称:

_class__attribute

这种行为被称为名称改写(name mangling)。这样一来,我们就无法从外部访问直接访问 __attribute 属性:

instance.__attribute

不过,我们还是可以通过 _class__attribute 访问变量:

instance._class__attribute

以下示例重新定义了 Counter 类:

class Counter:
    def __init__(self):
        self.__current = 0

    def increment(self):
        self.__current += 1

    def value(self):
        return self.__current

    def reset(self):
        self.__current = 0

此时,如果我们访问 __current 属性,将会返回一个错误:

counter = Counter()
print(counter.__current)
AttributeError: 'Counter' object has no attribute '__current'

但是我们可以通过 _Counter___current 访问 __current 属性:

counter = Counter()
print(counter._Counter__current)
0

总结

  • 封装是将数据和方法打包成一个类,从而隐藏信息和限制外部访问。
  • 按照惯例,单下划线前缀的属性被视为私有属性。
  • Python 会对双下划线前缀的属性进行名称改写。
开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系

以上是关于Python面向对象编程第08篇 私有变量的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象编程第06篇 实例变量

Python面向对象编程第06篇 实例变量

Python面向对象编程第03篇 类变量

Python面向对象编程第03篇 类变量

Python面向对象编程第09篇 再谈类变量

Python面向对象编程第09篇 再谈类变量