什么是private

StackOverflow上有一个备受关注的问题,想必也是很多刚从Java等支持面向对象范式的编程语言转来的同学想问的:Python的类是否可以定义私有变量(private variable)?

有兴趣的同学可以直接翻阅一下原问题以及大神们的回答

私有变量的概念要从面向对象中的封装谈起。我们定义一个类/对象,本质上是在描述这个类/对象的状态和行为,其中状态由成员变量表示,行为由成员方法表示。在这些状态和行为中,有些我们需要公开作为外界调用的接口,有些我们需要隐藏作为内部具体的实现。

举个例子说明一下,加入我们要定义一个Lady类,用于描述一位女士,那么表示女士年龄的状态变量age就需要设置成私有变量,调用者不能轻易访问,不过,可以定义一个

在Java中,在成员变量和成员方法的声明前加上private修饰符,即可使得该变量(方法)成为私有变量(方法),一旦声明为private,则该变量(方法)对于外部调用者不可访问。

我们今天要讨论的问题是,该封装机制在Python中是怎样的实现的。

不存在的

Python中没有禁止访问类中某一成员的保护机制。Java是一门非常工程化的语言,其哲学就是为工程服务,通过各种限制,尽可能减少程序员编写错误代码的机会。而Python则相反,其哲学为信任编码者,给程序员最少的限制,但程序员必须为自己编写的代码负责。

那是否意味着Python认为面向对象编程不需要封装呢?答案也是否定的。Python通过编码规范而不是语言机制来完成封装,具体而言,Python规定了对变量命名的公约,约定什么样的变量名表示变量是私有的,不应该被访问(而不是不能被访问)。

根据PEP 8的建议:https://www.python.org/dev/peps/pep-0008/#designing-for-inheritance

Always decide whether a class's methods and instance variables (collectively: "attributes") should be public or non-public. If in doubt, choose non-public; it's easier to make it public later than to make a public attribute non-public.

...

We don't use the term "private" here, since no attribute is really private in Python (without a generally unnecessary amount of work).

在设计类时,一定要明确类的成员变量和方法是否公开,如果暂不确定,则不公开,因为把一个私有变量修改为公开变量要比把一个公开变量修改为私有变量更简单。但是Python中一般不用private这个属于,因为Python里没有真正的private机制。

官方文档进一步解释了我们应该怎样通过编码规范来实现封装:https://docs.python.org/3/tutorial/classes.html#private-variables

“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.

Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

在Python中,没有绝对在外部访问不了的变量,但Python代码应遵循一个规范:以单个下划线开头的变量或方法应被视为非公开的API,因此不用特别声明,外部的调用者也不应该去访问以单下划线开头的变量或方法,因为类的设计者也遵循着这个规范,他会默认外部的调用者不会访问这种变量。

另外,Python通过一个非常简单的机制完成了一个伪私有化功能,这个机制名叫名称转写(name mangling):以双下划线开头,并以最多一个下划线结尾的标识符,例如__X,会被转写为_classname__X,其中classname为类名。这个机制实现起来非常简单,而且很大程度避免了调用者的误访问,但并不能像Java的private限定符那样完全杜绝外部的访问。我们以代码直观展示:

class A():

def __init__(self):

self.__private_var = 7

>>> a = A()

>>> print(a.__private_var)

AttributeError:

'A' object has no attribute '__private_var'

>>> print(a._A__private_var)

7

需要注意的是,Python的魔术方法,比如__len__, __bool__等不受此限制,因为它们均以双下划线结尾。

class B():

def __len__(self):

return 7

>>> b = B()

>>> print(b.__len__())

>>> 7

为什么需要名称转写

既然单下划线开头的变量名约定足以提醒调用者这是一个非公开变量,为什么还需要双下划线开头的变量进行名称转写呢?这涉及到面向对象中另一个重要概念,继承。

在Java中,声明为private的成员不会从父类被继承到子类,而Python中没有这样的强制机制。而进行名称转写则能有效避免子类中方法的命名冲突。

举一个具体的例子,我们知道,定义子类的时候,经常会调用父类的__init__()方法,假如父类的__init__()方法调用了父类的非公开函数__initialize(),当我们在子类中也需要__initialize()函数时会造成父类__init__()的异常行为,而名称转写避免了这一冲突,父类的__init__()实际上调用的是_父类名_initialize()。

总结

Python中不存在只能从对象内部访问的“私有(private)”变量,但Python制定了以下公约:以单下划线开头的成员变量或方法,是设计者不想暴露给外部的API,使用者不应该进行访问。

以双下划线开头且以至多一个下划线结尾的成员变量或方法,会进行名称转写。

至于Python为什么通过这样不够强力的手段进行约束,这源于Python这门语言的文化和哲学:简单至上。

python私有变量_[Python]Python中的私有变量相关推荐

  1. 继承能够访问父类私有字段_在单元测试中访问私有字段

    继承能够访问父类私有字段 首先,让我大声说一下,您需要将代码设计为可测试的,以便通过公共方法测试私有字段. 但是,(" buts"是人们仍在编程而不是计算机本身的原因,所以在这里很 ...

  2. julia在mac环境变量_在Julia中找到值/变量的类型

    julia在mac环境变量 To find the type of a variable/value, we use the typeof() function – it accepts a para ...

  3. julia在mac环境变量_在Julia中确定值/变量的类型

    julia在mac环境变量 To determine the type of value, variable – we use typeof() function, it accepts a valu ...

  4. mysql 表变量_在MySQL中创建表变量

    也许临时表会做你想要的.CREATE TEMPORARY TABLE SalesSummary (product_name VARCHAR(50) NOT NULL, total_sales DECI ...

  5. python 概率分布模型_使用python的概率模型进行公司估值

    python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...

  6. python 时间序列预测_使用Python进行动手时间序列预测

    python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...

  7. python设置环境变量_小白Python进行中

    一.安装 安装包的下载 在官网进行下载,我选用Python3.8.0. Welcome to Python.org​www.python.org 安装 安装的时候可以借鉴该视频. Windows 10 ...

  8. python定义方法self会被当作变量_为什么Python必须在方法定义和调用中显式使用“self”?...

    为什么Python必须在方法定义和调用中显示使用"self"? 这个想法借鉴了 Modula-3 语言.出于多种原因它被证明是非常有用的. 首先,更明显的显示出,使用的是方法或实例 ...

  9. python中class变量_对python 中class与变量的使用方法详解

    python中的变量定义是很灵活的,很容易搞混淆,特别是对于class的变量的定义,如何定义使用类里的变量是我们维护代码和保证代码稳定性的关键. #!/usr/bin/python #encoding ...

  10. python保存变量_将python 中的变量保存到本地

    如何将python中的变量保存在本地? 将python 的一些代码保存在本地, 特别是一些需要大量运算的结果,例如 机器学习里面的模型,,放在本地,还是比较好用的.下次就可以直接拿出来使用就好. 其实 ...

最新文章

  1. R语言droplevels函数删除因子变量(factor)没有用到的级别(level)实战
  2. Linux中的动态库和静态库(.a/.la/.so/.o)
  3. OpenCV进阶篇视频
  4. 爬取虎牙之三:通过json数据获取所有直播情况
  5. 陌陌的 Service Mesh 探索与实践
  6. 第一章:Understanding web performance-理解web性能
  7. mysql python 中文_python操作mysql中文显示乱码的解决方法
  8. 真的能去太空旅游了!单人票价......打扰了!
  9. SQLite内部机制和新特性
  10. windows痛苦面具-C盘瘦身法
  11. 第七版(谢希仁)计算机网络 知识点总结
  12. 2018年TI杯大学生电子设计竞赛题C-无线充电电动小车 题目加答案,非常详细
  13. 联想怎么进入linux界面,联想(Lenovo)为何重返Linux桌面?
  14. 十六进制加减乘除运算c语言,16进制加减乘除计算器
  15. Ubuntu下载安装VSCode(解决安装失败问题)
  16. 【若依框架】集成JWT
  17. 裴波那契数列的递归和动态规划算法
  18. EPICS记录参考2--EPICS过程数据库概念
  19. P1567_统计天数
  20. SIM逻辑模型与APDU

热门文章

  1. C语言中的按位操作符~介绍
  2. linux 权限管理 改变groupid,如何在linux下修改组权限
  3. 压缩解压命令(gzip、gunzip | tar | zip、unzip | bzip2、bunzip2)
  4. ExifInterface 介绍
  5. linux的su,su - 和sudo的区别
  6. Log4j2+ELK使用说明
  7. js拼接html 反斜杠形式,变量中的JavaScript反斜杠(\)导致错误
  8. MySQL如何实现select into 临时表的功能
  9. MSP430F5529学习笔记(一)——点灯|IO输出
  10. 夏日街头新风尚 | 变色镜片