靠默契保证的私有制:Python 中的私有

人类文明开化以来,私有制似乎是人类历史的主流在西方国家,“私有财产神圣不可侵犯” 是很多资本主义国家的立国原则之一。在我国,“私有财产不可侵犯” 也是写在宪法中的。在人类社会中,私有制表面由由法律保证,实质上是有法律背后的国家强制力保证。

试图反映世界万物的编程语言,便也产生了私有的概念。在大部分面向对象的编程语言中,对象可以设置其变量和方法为私有。私有变量和方法只能自己使用,即使其子对象都不能访问。大部分编程语言中的私有制,和现实生活中的私有制一样,也是有强制力保证的。只是这部分强制力来自编程语言本身。比如下面的 Java 代码

public class Person{
   private int money = 0
}

Java 语言强制地让 money 只能内部访问。但并不是所有编程语言都是这样的,Python 就是其中一朵奇葩。Python 中的私有制是由默契保证的。

1. Python 中的私有制

我们知道 Python 是一门很随意的编程语言,并没有由语言提供的权限控制机制。虽然 Python 对象中的所有属性都可以被外界访问,但我们可以构造出一个伪私有来,如下面的代码。

class Person:
    def __init__(self): 
       self.__age = 10

上面的代码定义了一个 Person 类, 有 __age 表示的年龄属性。神奇的事情发生了:

>> p = Person()
>> p.__age
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: Person instance has no attribute '__age'

Person 的对象中没有年龄属性。噢耶,私有制完成。这个现象的原理简单明了:以 __ 打头并且不以 __ 结尾的属性变量,都会自动更名为 _类名__变量名。比如上面的 __age 实际名字是 _Person__age。如果外界不认这个私有,直接访问 _Person_age 是可以破坏这个私有制的。所以这个私有制是建立在开发者之间的默契的基础上:“你既然这么设计了,说明这个变量你不希望我访问或者修改,那我就不访问或者修改了”,并不是建立在强制力的基础上。

2. 访问权限控制

私有制的一个大用处就是控制访问,让一些变量可读不可写。比如写成下面那样,我们就可以通过 age() 访问年龄属性了。

class Person:
    def __init__(self): 
       self.__age = 10
    def age(self):
       return self.__age

对于 Python 可读不可写变量,我们需要注意有两点和其他语言不一样。第一点是 Python 提供了 property 修饰符,可以让函数看起了像变量,但最好不用。这是因为看起来像变量,不是很熟悉内部机制的开发者很容易去改动它,比如下面的例子。

class Person:
    def __init__(self): 
       self.__age = 10
    @property
    def age(self):
       return self.__age
>> p = Person()
>> p.age
10
>> p.age = 25
>> p._Person__age
10
>> p.age
25

p.age = 25 是构建了一个新变量 age = 25, 原来的 .age 就不见了。这时候虽然实际的年龄属性 _Person__age 并没有被改变,但程序通过 .age 访问不到它了。

第二点是需要注意聚合类型的属性变量。聚合类型变量中的 list, set 和 dict 中的元素可变。如果一个对象的属性变量是这些聚合类型,那么可以通过修改其元素的方式改变其内容,如下所示。

class Person:
    def __init__(self): 
       self.__lessons = ["Chinese","English","Math"]
   
    def lessons(self):
       return self.__lessons
>> p = Person()
>> p.lessons
["Chinese","English","Math"]
>> p.lessons[0] = "CS"
>> p.lessons
["CS","English","Math"]

解决这个问题的办法就是用 tuple, fronzenset 和 fronzendict。

class Person:
    def __init__(self): 
       self.__lessons = ["Chinese","English","Math"]
   
    def lessons(self):
       return tuple(self.__lessons)

3.RoomAI 的例子

最近在开发非完美信息游戏 AI 环境:RoomAI。RoomAI 的目标是提供一些非完美信息游戏环境和一些基线模型算法,方便 AI 开发人员快速地构建、测试和对比自己的非完美游戏 AI 算法。目前 RoomAI 已经支持德州、梭哈和七鬼。RoomAI 的基本流程如下所示:玩家 AI 获得游戏环境给出的信息,当前玩家 AI 选择合适的动作,游戏环境根据该动作推进游戏逻辑;重复上述过程,直到分出胜负。给玩家 AI 的信息必须进行访问权限控制,那么玩家 AI 有可能通过信息获取游戏秘密或者操纵游戏。

为了实现这个目的,之前的做法是深度拷贝游戏环境给出的信息。了解了 Python 私有和访问权限控制,我们很容易想到用这套机制改造之。改造之后,我们通过 RoomAI 中 5 个 AI 对战 10000 局七鬼游戏实验,对比拷贝方法和访问控制方法的效率。

原始copy方案

改进copy方案

访问控制方案

371.73s

59.21s

26.56s

其中原始 copy 是直接使用 copy.deepcopy 进行拷贝,改进拷贝是自己实现了 __ deepcopy __ 函数(为什么要自己实现 __ deepcopy __ 的资料),访问控制则是使用私有变量从而使得信息可读不可写。很明显地,访问控制方法效率比拷贝方法高不少。

4.总结

试图反映世界万物的编程语言也有私有的概念。在大部分面向对象的编程语言中,对象可以设置其变量和方法为私有。私有变量和方法只能自己使用,即使其子对象都不能访问。大部分编程语言中的私有制,和现实生活中的私有制一样,也是有强制力保证的。只是这部分强制力来自编程语言本身。但并不是所有编程语言都是这样的,Python 就是其中一朵奇葩。Python 中的私有制是由默契保证的。私有制的作用之一就是访问控制,可以使得某些属性可读不可写。我们将这个做法用到非完美信息游戏 AI 环境 RoomAI 中,提高了运行效率。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏斑斓

作为Scala语法糖的设计模式

Scala算是一门博采众家之长的语言,兼具OO与FP的特性,若使用恰当,可以更好地将OO与FP的各自优势发挥到极致;然而问题也随之而来,倘若过分地夸大OO特性,...

3215
来自专栏代码世界

6大设计原则总结

6大设计原则总结 一、单一职责原则  单一职责原则:英文名称是Single Responsiblity Principle,简称是SRP。定义:应该有且仅有一个...

2669
来自专栏IT笔记

JAVA工作三年面试(二)

这里讲述下第二家公司的面试,这是一家大型互联网公司,简称W,一般像博主这样的传统行业去跳到这种公司简直是要跪舔的节奏,所以从一开始就带着一份敬仰之情去面试。由于...

3567
来自专栏大数据挖掘DT机器学习

新手学python 如何求职拿offer?

从八月底开始找工作,短短的一星期多一些,面试了9家公司,拿到5份Offer,可能是因为我所面试的公司都是些创业性的公司吧,不过还是感触良多,因为学习Python...

3306
来自专栏一个会写诗的程序员的博客

光剑评注:其实,说了这么多废话,无非就是: 一切皆是映射。不管是嵌套 XML,还是 Lisp 嵌套括号,还是 XXX 的 Map 数据结构,一切都是树形结构——映射。Lisp的本质(The Natur

http://www.defmacro.org/ramblings/lisp.html

622
来自专栏牛客网

cvte面经

一面:现场面去的很早明显焦虑并问不到面经(50分钟) (1)自我介绍这里介绍完提到自己熟悉的知识,项目 (2)项目介绍项目中遇到的难点如何解决的 (3)集合框架...

3687
来自专栏MelonTeam专栏

《实现模式》读书总结

导语 这是一本关于如何写好代码的书,是一本关于“如何编写别人能看懂的代码”的书。从价值观、原则、模式三个层面解读如何优化代码结构,减少代码维护成本。 ...

2048
来自专栏CDA数据分析师

如何拿到半数面试公司Offer——我的Python求职之路

从八月底开始找工作,短短的一星期多一些,面试了9家公司,拿到5份Offer,可能是因为我所面试的公司都是些创业性的公司吧,不过还是感触良多,因为学习Python...

2228
来自专栏牛客网

今日头条三面面经

4.       优先队列的底层数据结构?插入和删除一个节点的时间复杂度是多少? 

1022
来自专栏王肖的UT

《实现模式》读书总结

这是一本关于如何写好代码的书,是一本关于“如何编写别人能懂的代码”的书。

37311

扫码关注云+社区