什么是伪私有属性?

在Python中,没有类似 private 之类的关键字来声明私有方法或属性。

Python中要声明私有属性,需要在属性前加上双下划线(但是结尾处不能有双下划线),如:self.__a。然而这样的什么方式并不是真正私有,而是“伪私有”。

Python的伪私有属性,实际是通过变量名压缩(mangling)来实现变量名局部化。变量名压缩的规则:在初始的变量名头部加上一个下划线,再加上类的名称,最后是初始变量名的名称。

执行以下代码来验证:

class A(object):
def __func(self):pass if __name__ == '__main__':
print(A.__dict__)

运行结果:

{'__weakref__': <attribute '__weakref__' of 'A' objects>, '__module__': '__main__', '__doc__': None, '_A__func': <function A.__func at 0x10cfa037
8>, '__dict__': <attribute '__dict__' of 'A' objects>}

我们通过类的__dict__属性,将class A的所有属性打印出来,从打印的结果可以发现:原先定义的伪私有属性(方法):__func 在__dict__中并不存在,取而代之的是_A_func这个方法,方法__func的变量名被压缩。

如此在外部调用class A的__func方法时,会提示无法找到。修改代码进行测试:

class A(object):
def __func(self):pass if __name__ == '__main__':
a = A()
a.__func()

运行后出现异常,提示A没有属性__func,从而实现类似私有属性的功能。

AttributeError: 'A' object has no attribute '__func'

之所以说它是“伪私有”,是因为在了解伪私有变量的变量名压缩规则后,可以根据压缩规则进行调用。

再次修改代码进行验证:

class A(object):
def __func(self):print('Hello Python') if __name__ == '__main__':
a = A()
a._A__func()

运行结果正常, 成功打印“Hello Python”字符串。

Hello Python

所以,Python的类并不存在正在的私有属性,通过双下划线实现的伪私有属性,本质上是对变量名进行压缩,使之无法直接在外部调用。

为什么要使用伪私有属性

使用伪私有属性是为了避免在类树中,多个类赋值相同的属性引发冲突问题。

假设有两个类,C1 和 C2,他们都有相同的属性X。

class C1():
def meth1(self):
self.x = 'Hello World'
def meth2(self):
print(self.x)
c1 = C1()
c1.meth1()
c1.meth2()
class C2():
def meth3(self):
self.x = 'Hello Python'
def meth4(self):
print(self.x)
c2 = C2()
c2.meth3()
c2.meth4()

类C1和C2在单独调用时,输出结果没有问题,符合预期:调用meth2方法时,打印meth1的赋值结果;调用meth4方法时,打印meth3的赋值结果。

此时增加一个新的类C3,继承自C1、C2(多重继承):

class C1():
def meth1(self):
self.x = 'Hello World'
def meth2(self):
print(self.x) class C2():
def meth3(self):
self.x = 'Hello Python'
def meth4(self):
print(self.x) class C3(C1, C2):
pass c3 = C3()
c3.meth1()
c3.meth3()
c3.meth2()
c3.meth4()

从运行结果可以看出,每次 print(self.x)的内容,取决于 self.x 最后一次赋值的内容。

Hello Python
Hello Python

在示例代码中,先调用 c3.meth1() 进行赋值,self.x的值为“Hello World”,再调用 c3.meth3() 进行赋值时,self.x的值被覆盖,目前的值为“Hello Python”。

后续再调用c3.meth2()打印self.x的值时,实际上打印的是最后一次赋值结果,这在有些情况下跟类的设计初衷是相违背的:在C1中,meth2希望打印的是在meth1中赋值的内容:“Hello World”。

在使用伪私有属性后可以解决变量名self.x相互覆盖的问题(因为self.__x 被压缩成了 self._C1__x 和 self._C2__x,变量名不同,不会互相覆盖):

class C1():
def meth1(self):
self.__x = 'Hello World'
def meth2(self):
print(self.__x) class C2():
def meth3(self):
self.__x = 'Hello Python'
def meth4(self):
print(self.__x) class C3(C1, C2):
pass c3 = C3()
c3.meth1()
c3.meth3()
c3.meth2()
c3.meth4()

运行结果符合C1的设计初衷:调用meth2时应该打印出meth1的赋值结果:

Hello World
Hello Python

Python的伪私有属性的更多相关文章

  1. Python面向对象之私有属性和方法

    私有属性与私有方法 应用场景 在实际开发中,对象的某些属性或者方法 可能只希望在对象的内部被使用,而不希望在外部被访问到: 私有属性 就是对象不希望公开的属性: 私有方法 就是对象不希望公开的方法: ...

  2. Python面向对象之私有属性和私有方法

    01. 应用场景及定义方式 应用场景 在实际开发中,对象 的 某些属性或方法 可能只希望 在对象的内部被使用,而 不希望在外部被访问到 私有属性 就是 对象 不希望公开的 属性 私有方法 就是 对象  ...

  3. Python 类的私有属性与私有方法

    1.隐藏的使用场景 在Python类中,有些属性和方法只希望在对象的内部被使用,而不希望在外部被访问到, 2.定义方式, 在属性名或方法名前增加两个下划线,定义的就是私有属性或方法 #其实这仅仅这是一 ...

  4. python 类的私有属性和方法 (转载)

    转载:http://www.runoob.com/python/python-object.html 类属性与方法 类的私有属性 __private_attrs:两个下划线开头,声明该属性为私有,不能 ...

  5. Python 安全修改私有属性

    设置私有属性之后,如何修改私有属性 class Room: def __init__(self,name,length,width): self.__name = name self.__length ...

  6. Python中的私有属性私有方法、类属性类方法以及单例设计模式

    私有属性是对象不希望公开的属性,私有方法是对象不希望公开的方法.在定义私有属性和私有方法时,在属性或者方法前,加上__(两个下划线) 公有方法可以通过对象名直接调用,私有方法不能通过对象名直接调用,只 ...

  7. Python类的私有属性

    class Bar(object): __age = 18 sex = 'male' def __init__(self, ): pass def f(self): print(self.__age) ...

  8. Python高级语法-私有属性-名字重整(4.7.1)

    @ 目录 1.说明 2.代码 关于作者 1.说明 使用__dict__魔法方法 可以看到所有的属性,包括公有的,私有的,保护的等等 不能调用的原因就是,解释器把名字属性给重组了 其实是可以访问到的 2 ...

  9. Python高级语法-私有属性-with上下文管理器(4.7.3)

    @ 目录 1.说明 2.代码 关于作者 1.说明 上下文管理器 这里使用with open操作文件,让文件对象实现了自动释放资源.我们也能自定义上下文管理器,通过__enter__()和__exit_ ...

随机推荐

  1. 关于hue安装后出现KeyError: "Couldn't get user id for user hue"的解决方法

    首先说明出现此问题的原因是因为你使用的root用户安装了hue,然后在root用户下使用的build/env/bin/supervisor,如下图所示那样: 知道了原因,就容易解决问题了.首先要创建个 ...

  2. Python函数篇(5)-装饰器及实例讲解

    1.装饰器的概念   装饰器本质上就是一个函数,主要是为其他的函数添加附加的功能,装饰器的原则有以下两个: 装饰器不能修改被修饰函数的源代码 装饰器不能修改被修改函数的调用方式   装饰器可以简单的理 ...

  3. spring 4 升级踩雷指南

    spring 4 升级踩雷指南 前言 最近,一直在为公司老项目做核心库升级工作.本来只是想升级一下 JDK8 ,却因为兼容性问题而不得不升级一些其他的库,而其他库本身依赖的一些库可能也要同步升级.这是 ...

  4. WebStorm10 控制台中文乱码解决方案

    工作时发现无论是使用ctrl+F搜索还是查看提交的注释中文都是口,看的本小白十分蛋疼菊紧,所以抽时间找了方法去搞定它. 首先点击左上角的File,选择Setting 然后选择Appearance &a ...

  5. 多域名环境,页面获取url的一种方案

    因为系统是分布式部署的.而且有多个域名,所以常常涉及到获取url的问题. 这是系统框架层面须要提供的能力.否则每一个模块都须要自己去想办法获取ip,就会非常混乱.上线也easy发生bug 主要须要解决 ...

  6. vue-router实例

    最近刚刚用vue写了个公司项目,使用vue-cli构建的,算是中大型项目吧,然后这里想记录并且分享一下其中的知识点,希望对大家有帮助,后期会逐渐分享:话不多说,直接上代码!! main.js // T ...

  7. Java二维数组的概念和使用方法

    二维数组 数组的数组---二维数组的每一个元素是一个一维数组 定义格式 数据类型[][] 数组名 = new 数据类型[二维数组的长度/包含的一维数组的个数][每个一维数组的长度]; int[][] ...

  8. 配置Meld为git的默认比较工具

    1. 安装 meld sudo apt-get install meld 2. 创建 git_meld.sh 脚本 cd /bin vim git-meld.sh #!/bin/sh meld $2 ...

  9. Aop介绍及几种实现方式

    Aop介绍      我们先看一下wiki百科的介绍     Traditional software development focuses on decomposing systems into ...

  10. UITableView的性能优化1

    UITableView作为ios中使用最频繁的控件之一,其性能优化也是常常要面对的,尤其是当数据量偏大并且设备性能不足时.本文旨在总结tableview的几个性能优化tips,并且随着认识的深入,本文 ...