我来自Java世界,阅读Bruce Eckels的Python 3模式、食谱和习语。
在阅读关于类的内容时,它继续说在Python中不需要声明实例变量。你只需要在构造器中使用它们,Boom,它们就在那里。
例如:
1 2 3 4 5 6 7 8 9 10
| class Simple:
def __init__(self, s):
print("inside the simple constructor")
self.s = s
def show(self):
print(self.s)
def showMsg(self, msg):
print(msg + ':', self.show()) |
如果是这样,那么类Simple的任何对象都可以在类外更改变量s的值。
例如:
1 2 3 4 5
| if __name__ =="__main__":
x = Simple("constructor argument")
x.s ="test15" # this changes the value
x.show()
x.showMsg("A message") |
在Java中,我们已经学习了公共/私有/受保护变量。这些关键字是有意义的,因为有时您希望类中没有人可以访问的变量。
为什么在Python中不需要这样做?
- 你的意思是实例变量,而不是类变量,对吗?
- 您应该检查属性:docs.python.org/library/functions.html属性。只需使用getter,您的变量就会受到保护。
- 你为什么用self1,btw?
- 虽然这不是很流行,但是可以通过闭包来私有化变量。本文对此进行了详细的解释。其思想是赋予类方法对外部作用域中定义的变量的特权访问权。这种做法在JavaScript中很常见。
- @本篇文章仅供受邀读者阅读…
- 再说一遍,你为什么要用self1?
- @这篇文章是私人的。多么讽刺啊!
这是文化。在Python中,您不会写入其他类的实例或类变量。在Java中,如果你真的想做的话,没有什么能阻止你做同样的事情。毕竟,你总是可以编辑类本身的来源来达到同样的效果。Python放弃了安全性的伪装,鼓励程序员负起责任。在实践中,这是非常好的工作。
如果出于某种原因想要模拟私有变量,则可以始终使用PEP8中的__前缀。Python将变量命名为EDCOX1(1),这样它们就不容易在包含它们的类之外进行编码(尽管如果你足够确定,你可以绕过它,就像你在工作时可以绕过Java的保护)一样。
按照同样的惯例,_前缀意味着远离,即使在技术上没有阻止你这样做。您不必使用其他类的变量,这些变量看起来像__foo或_bar。
- 这是有道理的。不过,我认为Java中没有任何方法可以访问类外的私有变量(除了实际改变类的源代码之外)。有?
- 有趣的是,我来自一个PHP背景,我想知道这在实践中是如何工作的。如果所使用的语言不是python,那么类能够修改私有成员是不是很危险?
- 我不知道,但重点是你可以编辑源代码,甚至编译的字节码。如果你有足够的决心去摆弄那个班的内部,没有什么能阻止你。所以,为什么要花费精力去阻止它,而不是依靠公约和薄弱的机制来说"不要这样做!"归根结底,不管一个想法通常有多糟糕,有时候你真的很想在你不该去的地方闲逛。
- @大卫-假设我们都是成年人。不要破坏你无法修复的东西!在这种情况下,这意味着你不应该和那些私人会员,比如说"foo"或者"bar"混在一起。同样,在实践中,如果没有一个非常好的理由,这是不可能的。理论上它可能并不纯粹,但我从未见过现实世界中的问题。
- +1:我们都是成年人。"private"和"protected"关键字是有趣的注释,但变量名的前导_也是如此。python是分布式的——并运行——作为源代码。没有用于隐藏实现的".class"文件。
- 我倾向于使用Python的方式,但我不认为Java的方式是没有意义的。快速声明私有的东西会告诉阅读代码的人一些非常有用的东西:这个字段只在这个类中被修改过。
- python中的foo也是如此,而bar意味着您可以,但可能不应该。
- @无所不在,你可以使用反射。
- 重要的是你要写一个好的代码,它能整洁高效地解决你的问题。任何想要破解你的代码的人最终都会这么做。但他们可能应该把时间花在正确的编码上。
- 可能太少太晚,但是Java代码中的访问修饰符在Java代码在配置了安全性管理器的JVM中运行时具有非常真实的安全含义。配置SecurityManager时运行的代码不能绕过访问修饰符限制。
- 有公共的、私有的和受保护的来强制访问,而不是Python的"自愿"强调约定。与python不同,在ruby中。在许多解释语言(如ruby)中,php中的可见性有一个可见性概念,但在python中没有,在python中,它们具有文化性。
- @如果说伊恩?M?班克斯教会了我什么,那就是文化总是胜利的。
- 同样值得注意的是,作为一种或多或少的解释语言,C++编译器(和Java编译器)可能有很多考虑,在Python中根本不存在。私有属性或方法可以进行各种优化以加快从本地对象访问的速度。上面写着"嘿,编译器,我只会从这个对象中被访问,所以不要担心所有的文书工作,让我从外部可见,如果这有帮助的话,你甚至可以直接插入我"。在Python的情况下,这是一种情绪。
- 我直截了当地说,所以python不实现公共或私有属性,因为"它是安全的借口,鼓励程序员负责",但是社区鼓励使用"u"来表示私有变量和方法?也许Python应该公开和私有不?它们的主要目的是告诉您应该使用什么API与类进行交互。它们是一个文档,告诉您使用这些方法,而不是使用那些方法。它们不是"安全的伪装",它们是API文档,甚至可以由IDE用来指导您!
- python确实具有公共、半公共和私有变量:foo、_foo和__foo。IDES和其他工具支持这些,并调用对类内部的外部引用。但同样的,它并没有强化这一点:如果你下定决心要逃离沙箱,那么,继续前进,但是不破坏东西的责任就在你身上。
- 一些似乎还没有被特别提到的东西是可见性,这使得调试更容易:如果您有问题,并且该方法或变量超出了某些代码的范围,您知道代码没有调用将错误值应用到某个变量的函数,或者直接(但错误地)修改该变量。在python中使用"uuuu",您不能保证它,但它变得不太可能。在其他语言(Java,C++)中,它当然是有帮助的(即使它对想要添加/修改特征的开发者造成惊愕)。
- @无所不在:是的,你可以。Java具有反射API:教程。Jekov.com/Java反射/ & Helip;"私有"在访问级别时一直是一个误导性的术语。更像是"隐藏在引擎盖下"。任何人都可以打开引擎盖,但大多数人不应该。
- LarryWall很好地表达了这一文化理念(对于Perl来说,在Perlmod5.0的主页上):"Perl不迷恋强制隐私。它更喜欢你呆在它的起居室外面,因为你没有被邀请,而不是因为它有一把猎枪。
- 你在保护它不受你自己的伤害。
- 反射并不是你"偶然"可以做的事情,而且据我所知,这是唯一处理私有变量的方法。令人惊讶的是,同时,python鼓励我们成为"负责任的"程序员,同时谈论即使是新手也可以如何用python编写代码!
- @AneeshBarthakur您也不能"意外"访问AnotherClass.__foo,因为您必须计算其特定于实现的派生名称。在CPython 3.5中,这看起来像AnotherClass._AnotherClass__foo。当然,这是可以克服的(只要您知道您的代码将在什么实现上运行!)但这是一个巨大的警告信号,你不应该这样做。
- 你是对的…从我遇到这条线到现在这段时间里,我在这个问题上学到了一些知识!
- @Aneeshbarthakur哦,酷!我们都在一起,一起学习。-)
- 这是一个很好的答案,你的推理当然是正确的,但我有一点不同意。访问修饰符的目的从来不是安全的。相反,它们是一种明确划分(并在很大程度上强制)类中哪些部分被认为是内部的,哪些部分暴露给该类的外部用户的方法。约定(文化)当然是访问修饰符的有效替代方法,两种方法都有其优缺点,但在通常意义上,语言级访问修饰符以任何方式都是"安全"的,这是误导性的。
- 它不是"Java方式",它是OOP方式或C++方式。
- python是oop,这不是python的方式,所以它不是一般的"oop方式"。
- 我们花了很多年的时间指望程序员要小心,不要碰不该碰的东西。猜猜看,意外发生了。这就是为什么公共/私有/保护被添加到许多语言中的原因。就像汽车报警器(或"俱乐部")一样,它们可以威慑整类小偷,但不能威慑铁杆小偷。没有什么能阻挡他们。公共/私人的目的是为了获得最大的回报,消除偶然发生的常见错误。
- @evvo您不会"意外"地键入一个前导下划线-所以每当您键入类似于someobj._attrib的内容时,您就会知道您破坏了封装。从这一刻起,你要对任何可能发生的不良后果负全责。
- @布鲁诺——各种各样的事情都是偶然发生的,那些匆忙的人,那些只想抄近路去接触其他事情的人,但是不小心想到你在另一个窗口打字。这就是能见度控制的目的,以避免此类事故或误解。尤其是在处理第三方软件时。作为一名开发人员,我花了很长时间,看到了你能想象到的各种"糟糕"。当涉及到纪律和严格性时,我对编译器的信任远远超过对人类的信任。
- @Evvo好吧,我作为专业程序员已经工作了20多年了,我自己也看到了不少失误,而且我肯定不信任这里的编译器——我宁愿相信一个好的linter和一个好的Unitttest报道。没有办法做一个白痴的证明语言——Java和艾达都失败了(以艾达的史诗般的方式)——所以我们不要妄自尊大,认为如果编译的话是正确的。
- 我得到了我正在寻找的答案——在Python中没有访问修饰符,但是有"黑客"使它们"接近私有"。然而,这个答案是一种"高马"的态度,试图贬低Java/C++(以及任何其他具有这些修饰语的语言)。作为一个长时间的Java开发人员,决定在Python上进行一个有趣的游戏,这个答案肯定是令人沮丧的:
- 嗨@saurabhsrivastava!这并不意味着士气低落或屈尊俯就。十年前我写这篇文章时,我笑了,今天我笑了。欢迎来到娱乐圈!
- 值得注意的是,私人和公共部门并不是真正的安全问题。如果一个坏人可以通过代码访问你的东西,你已经拥有了。它更多的是关于代码卫生、强制封装以及让编译器知道是编译成便宜的本地调用,还是稍微贵一些的方法调用。任何不属于契约的东西,都是私有的,所以当类通过这些私有调用调用自己时,编译器可以为这些调用生成更快的C样式调用。python信任您编写健康的代码,并且作为一种解释语言,编译器优化并不重要。
- 当用户键入dir(SomeObject)并看到一个以下划线开头的诱人的命名属性时,他们(或我)很有可能会尝试使用它。通常是为了阅读,为什么不设置好呢?我认为任何数量的下划线都不会自然地或明显地使传统意义上的任何东西"私有化"(明显性通常是关于Python最好的东西)。如果他们不出现在dir()或help()等网站上,那会使他们更"私人化"。
- 酷,更容易学习
python中的私有变量或多或少是一种黑客行为:解释器故意重命名变量。
1 2 3 4 5
| class A:
def __init__(self):
self.__var = 123
def printVar(self):
print self.__var |
现在,如果您试图访问类定义之外的__var,它将失败:
1 2 3 4
| >>>x = A()
>>>x.__var # this will return error:"A has no attribute __var"
>>>x.printVar() # this gives back 123 |
但是你可以很容易地摆脱这个问题:
1 2 3 4 5
| >>>x.__dict__ # this will show everything that is contained in object x
# which in this case is something like {'_A__var' : 123}
>>>x._A__var = 456 # you now know the masked name of private variables
>>>x.printVar() # this gives back 456 |
您可能知道OOP中的方法是这样调用的:x.printVar() => A.printVar(x),如果A.printVar()可以访问x中的某个字段,那么这个字段也可以在A.printVar()之外访问……毕竟,函数是为可重用性而创建的,里面的语句没有特殊的权力。
当涉及编译器时,游戏是不同的(隐私是编译器级别的概念)。它知道带有访问控制修饰符的类定义,因此如果在编译时不遵循规则,它可能出错。
- 简而言之,这不是封装
- 我想知道PHP是否有类似于其愚蠢的私有变量的东西-因为私有变量在解释语言中没有真正意义-我的意思是,如果不编译x变量,它能做什么优化呢?
- 我们如何随机化私有变量的模式?
- @克里森同样的问题
- 使用self.__dic__ = {}不允许使用__str__方法。在这种情况下,是否有使用__str__的工作?
- 实际上这不起作用。出现错误:AttributeError: 'A' object has no attribute '_A__var1'代码:gist.github.com/arsho/98db85456f57b92639faedcf7aff045a
- @你说得对,如果我能找到更好的解决方案,我会努力更新的。
- @crisron,您需要使用描述符,下面是重命名属性的示例
- @watashishun"简而言之,这不是封装"=>是的。封装只使用公共API,因此客户端代码不受实现更改的保护。命名约定是区分什么是API和什么是实现的一种完全有效的方法,关键是它只是起作用。
- 封装与是否可以通过复杂方法访问私有变量无关。任何人都可以直接访问具有"私有变量"的C++内存。python还可以访问"私有变量"。了不起的事。
- 另一方面,如果您为私有字段提供get和set方法,则可以安全地声明这些方法不是封装的!很明显,封装是一个设计问题,而不是语言特性。
正如上面许多注释所正确提到的,让我们不要忘记访问修饰符的主要目标:帮助代码用户理解应该更改的内容和不应该更改的内容。当你看到一个私人领域时,你不会把它搞得一团糟。所以它主要是语法上的糖分,很容易在python中通过u和uuu实现。
- 我认为这是最重要的一点。当调试代码时(我知道,我是个引入错误的懦夫),知道哪些类可以更改成员变量可以简化调试过程。至少,如果变量受到某个范围的保护。类似的概念是C++中的const函数。我知道其中的成员变量没有改变,所以我甚至不把这个方法看作是导致变量设置错误的潜在原因。尽管它可以使类扩展的后续开发/添加特性,但是限制代码的可见性使调试更容易。
"在Java中,我们已经学习了公共/私有/保护变量"。
"为什么在python中不需要?"
出于同样的原因,Java中不需要这样做。
你可以自由使用或者不使用private和protected。
作为一个Python和Java程序员,我发现EDCOX1 5和EDCOX1 6是非常重要的设计概念。但作为一个实际问题,在数以万计的Java和Python行中,我从来没有真正使用EDCOX1 5或EDCOX1 6。
为什么不呢?
我的问题是"保护谁?"
我团队中的其他程序员?他们有源头。当他们可以改变它时,受保护意味着什么?
其他团队的其他程序员?他们在同一家公司工作。他们可以——通过电话——找到源头。
客户?这是雇佣编程的工作(一般)。客户机(通常)拥有代码。
那么,究竟是谁——确切地说——我在保护它不受伤害?
- 无所不在:我不知道翅膀,但我确实知道这一点——因为Java--我不怎么使用鸭子打字。如果我这样做了,我在Python中的效率可能会更高。我发现一个好的继承层次结构(一个可以转化为Java)通常是值得在Python中努力的。
- +1:最好的概念分析。
- @门廊:"让你的IDE很容易知道"…什么?我的IDE是一个编辑器。我是设计师。我知道设计是关于什么的。我的IDE是一个编辑器,什么都不知道。谁是神秘的"没人"谁"不小心使用了其他东西"?明确地?谁是那个人?为什么他们不知道使用API的正确方法?
- -我同意门廊。这不是禁止访问或隐藏某些内容,而是隐式API文档。开发人员以及编译器/解释器/代码检查程序可以很容易地看到推荐使用哪些成员,哪些成员不应该被接触(或者至少小心)。在大多数情况下,如果一个类或模块的所有成员都是公共的,那将是一个可怕的混乱。将私有/受保护/公共成员的区别视为一种服务,并说:"嘿,这些成员很重要,而这些成员在内部使用,可能对您没有用处。"
- @oben sonne:"隐式API文档"?什么?你的意思是让人们猜猜你的意图是什么?怎么会有人猜到?与为支持实际程序员的用例而编写的实际文档相比,public/private/protected似乎非常差。
- @S.lott:我同意API文档具有更高的优先级,并且通常是传达API预期用途的唯一方法。但有时会员的名字和知名度(就私人/公共而言)足以说明他们自己。另外,我也看到了您的观点,即隐式文档的思想在编辑器w/o api检查中不起作用,但它在IDE的代码完成中非常有用。假设您已经阅读过API文档一段时间了,它可以帮助您记住如何使用类。如果私人成员和公共成员之间没有区别,事情就不会那么聪明了。
- @奥本·索恩:"如果私人成员和公共成员之间没有区别,事情就不会那么聪明了?"东西?什么东西?"有代码完成的IDE?这就是不明智的做法吗?请阅读amazon.com/large scale software design john lakos/dp/0201633‌&8203;620。公共/私有/受保护合并了太多实际有用的东西。api文档通常传递更多的(和更有用的)private的信息。private只是信息太少,没有任何实际价值。
- 讨论进行得太晚了,但是Proculus和Oben在这里请求的所有内容都被"在其前面加下划线"的约定完美地处理了(并且不会造成编译器执行该约定所造成的伤害)。
- @ncoghlan编译器强制执行会造成什么危害?
- @其他人都看到了gamma,e.等人,设计模式(1995),p11和p13。
- @希韦伦:完全正确。完全同意。封装是一种设计特性。隐私并不能帮助我们将设计封装起来。它只提供编译器支持,以防止人们使用他们不应该使用的属性。对接口进行编程是一个有定义的接口并记录它的问题。private只是编译器支持,帮助那些不能阅读或拒绝阅读文档的人。
- @Hiwaylon按约定封装意味着,如果有充分的理由(例如,插入额外的日志以查找应用程序状态错误更新的来源),则可以中断封装。使用编译器级执行,你无法做很多事情,在维护和测试真实世界软件方面非常有用(看看Java和C++的设计模式:它们中的很多都是写很多额外的代码给你一些额外的扩展点)。
- @Hiwaylon这是一种"同意成人"的API设计方法,主要的下划线写着"如果你开始搞砸了,你就靠自己了,但是如果你认为有必要,语言不会阻止你"。另一方面,强制执行使最初的API设计者能够说"你不能以我没有预先计划的方式使用我的API"。即使您愿意承担相关的风险,编译器也不会让您这么做。"
- @NCoghlan这些观点在互联网上和大量的python出版物中都有。不会让它们成为经文。编译器对接口的强制执行、强大的数据封装和类型化被许多人认为是非常有益的。"隐私并不能帮助我们将设计封装起来。"同意不同意。"私密只是…帮助那些看不懂或拒绝阅读文档的人。"再一次,傻瓜。我们都同意,高级、松散类型语言和低级、强类型语言都有好处。它们都是工具箱中的工具!
- @Hiwaylon:如果你坚持把封装(一种设计技术)和隐私(一种实现技术)混为一谈,我可以理解为什么你声称隐私在魔法上是必不可少的。考虑一个C++程序员,它根本不使用EDCOX1 0。你是说一个好的封装好的设计会因为没有使用private而神奇地无法显示出好的封装吗?如果是这样,那么有选择地删除隐私的friend声明将使设计神奇地"不封装"。即使控制得很好?我一点也不买。
- 直接访问公共数据违反了封装。虽然下划线约定有助于传达意图,但在语言中存在private关键字肯定不是坏事。
- 我们不能有效地实现私有的、公共的、由聪明的元类保护的吗?
- 虽然我半同意,在Java中省略EDCOX1,1Ω/EDCX1,0表示并不意味着"不管发生什么"。它为成员提供了默认的可见性,这意味着它在包中是可见的,但在其他任何地方(包括子包)都不可见。在大多数情况下,您必须使用可见性来实现功能。
- 我以前认为私有公共有点傻,但是在正确使用类之后,在类上可能有大量非常小的函数,您希望能够添加仅指定用于该类中其他方法的方法。关键是,如果你知道在同一个类中从不同的方法调用这个方法只会有意义,那么就把它设为私有方法,如果你在外部,就不会考虑它。
- @洛特,我不是Python,所以我不会从这个角度评论。然而,作为Java开发人员,这确实是令人恐怖的建议。- 1
- 也许是为了防止我犯了愚蠢的错误?我同意访问修饰符帮助您解释代码的概念。它们提供编译时通知,说明编写库的人(假设他们知道自己在做什么)期望什么。我喜欢python,但说你在整个职业生涯中从未使用过private或protected,这似乎过于顽固。在没有文化约定的情况下(如在Python中),将您的意图传达给编译器是有价值的。在大多数支持它们的语言中,其他人希望您利用它们来传达您的意图。
- 这不全是执法吗?在Java中,编译器强制写入器的意图。在python中,缺少工作程序表明python解释器强制执行了写入的意图。OTHH,在运行时使用Java类不正确地指示没有读取文档或理解设计。在python中,它表示相同。这取决于你想让其他编码器使用什么,以及你想让他们如何发现如何使用它。所有这些都将使用文档。Java将使您在编译时(或之后)读取。程序崩溃时的python。
- 同意S.lott。如果整个点是使用的隐式指示,Python用下划线前缀来解决它,并且由于没有其他的点,正如我们已经得出的结论,Java的私有/公共是不必要的复杂。
- 私有变量和受保护变量执行良好的设计实践。我们都是人类,有时我们都会感到懒惰或疲倦。许多人不能强迫自己戒烟,或开始锻炼,即使他们知道什么对他们最好。同样,如果没有这样的障碍,很多人也会倾向于使用私有变量。宣布一些私密的事情是你要履行的承诺。其优点是,您几乎可以完美地封装一段代码,对其进行润色并感到安全。这种安全性在Python中从未发生过。
- 不同意,它提高了可读性,并帮助其他程序员知道方法是否应该使用,即使他们可以更改。
- 真的。你完全错过了这一点,你给出了一个非常糟糕的建议,你侮辱了任何在这一点上不同意你的人,但你仍然得到徽章和1000多个荣誉点的这个"答案"。
- +1但最后@s.lott已经发布了大约2500个帖子,并且在"python"标签上赢得了大约20000个声誉。语言只是一种语言,它可能有一些你永远不会同意的部分,但是作为一个好的程序员重要吗?答案很明显。
- 更不用说设计模式了,他还在软件工程SE站点上赢得了很多徽章。
下划线约定中存在私有变量的变体。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| In [5]: class Test(object):
...: def __private_method(self):
...: return"Boo"
...: def public_method(self):
...: return self.__private_method()
...:
In [6]: x = Test()
In [7]: x.public_method()
Out[7]: 'Boo'
In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()
AttributeError: 'Test' object has no attribute '__private_method' |
有一些细微的区别,但为了编程模式的思想纯洁性,它就足够好了。
有@private decorators的例子可以更紧密地实现这个概念,但是ymmv。可以说,还可以编写一个使用meta的类定义
- 我意识到这对派对来说已经很晚了,但是谷歌搜索这个问题时,这个链接会出现在谷歌上。这并不能说明整个故事。__x作为类内的变量A实际上被编译器重写为_A__x,它仍然不是完全私有的,仍然可以访问。
- 当然,如果我看到一个名为_A__x的变量,我不会去碰它。可能会传染。我要把它赶走。
- 马特恩有正确的想法。_ uux可以解释为"这里是龙"
python对私有标识符的支持有限,通过一个自动将类名前置到以两个下划线开头的任何标识符的特性。这在大多数情况下对程序员是透明的,但最终的效果是任何以这种方式命名的变量都可以用作私有变量。
更多信息请参见此处。
通常,与其他语言相比,Python的对象定向实现有点原始。但事实上,我喜欢这样。这是一个概念上非常简单的实现,非常适合语言的动态风格。
我唯一一次使用私有变量是当我向变量写入或从变量读取时需要做其他事情,因此我需要强制使用setter和/或getter。
正如前面所述,这同样适用于文化。我一直在做一些项目,在这些项目中,其他类变量的读写都是免费的。当一个实现被弃用时,识别使用该函数的所有代码路径需要更长的时间。当强制使用setter和getter时,可以很容易地编写调试语句来标识已调用不推荐使用的方法以及调用该方法的代码路径。
当您在一个任何人都可以编写扩展的项目中时,通知用户将在几个版本中消失的不推荐的方法,因此在升级时将模块损坏保持在最低程度是至关重要的。
所以我的答案是:如果您和您的同事维护一个简单的代码集,那么保护类变量并不总是必要的。如果您正在编写一个可扩展的系统,那么当对核心进行更改时,需要被使用代码的所有扩展捕获,这就变得非常必要。
如前所述,可以通过在变量或方法前面加下划线来指示它是私有的。如果你觉得这样不够,你可以一直使用property装饰。下面是一个例子:
1 2 3 4 5 6 7 8 9
| class Foo:
def __init__(self, bar):
self._bar = bar
@property
def bar(self):
"""Getter for '_bar'."""
return self._bar |
这样,引用bar的某人或某物实际上引用了bar函数的返回值,而不是变量本身,因此可以访问它,但不能更改它。然而,如果有人真的想这样做,他们可以简单地使用_bar,并为其分配一个新的值。没有一种可靠的方法可以阻止某人访问您希望隐藏的变量和方法,正如已经反复说过的那样。但是,使用property是您可以发送的最清楚的消息,即变量不可编辑。property还可以用于更复杂的getter/setter/deleter访问路径,如这里所述:https://docs.python.org/3/library/functions.html属性
私有和受保护的概念非常重要。但是python——这只是一个原型化和快速开发的工具,开发中可用的资源有限,这就是为什么在python中一些保护级别没有那么严格。您可以在类成员中使用"uuuu",它工作正常,但看起来不够好-对此类字段的每个访问都包含这些字符。
另外,您可以注意到python oop概念并不完美,smaltalk或ruby更接近纯oop概念。即使是C或Java更接近。
python是非常好的工具。但它是简化的OOP语言。从语法和概念上简化。Python存在的主要目标是使开发人员能够以非常快的方式编写具有高抽象级别的易于阅读的代码。
- rearson private和protected非常重要,因为在静态编译语言中,编译器可以创建对private方法的diirect调用,但必须依赖于公共方法的查找表。这对于动态语言来说并不是一个问题。最后,像C++这样的语言对继承和方法解析有影响。python和ruby有非常相似的OO实现,所以比较毫无意义。smalltalk实际上没有公共/私有消息的概念。您可以自由添加私密作为一个类别,但它纯粹是建议。
- 进一步证实我的主张。从编纂卫生的角度来看,@private(etc)装饰器对封装很重要,但对它来说并不是必需的,因此它比任何东西都更具咨询性,但是由于private/public在非静态语言中对优化没有任何帮助,因此它没有像ja这样的编译语言在深层次上实现。VA或C
很抱歉,伙计们"重修"了这条线,但我希望这能帮助一些人:
在Python 3中,如果你只想"封装"类属性,就像在Java中一样,你可以像这样做同样的事情:
1 2 3 4 5 6 7 8 9 10
| class Simple:
def __init__(self, str):
print("inside the simple constructor")
self.__s = str
def show(self):
print(self.__s)
def showMsg(self, msg):
print(msg + ':', self.show()) |
要实例化此操作,请执行以下操作:
1 2
| ss = Simple("lol")
ss.show() |
注意:print(ss.__s)将抛出一个错误。
实际上,python3会混淆全局属性名。把它变成一个"私有"属性,就像在Java中一样。该属性的名称仍然是全局的,但无法访问,就像其他语言中的私有属性一样。
但不要害怕。没关系。它也起作用。;)
- 这是从python 1.5.2iirc开始就存在的,并且它仍然不阻止通过其损坏的名称访问属性。
Python没有任何私有变量,如C++或Java。如果需要,也可以随时访问任何成员变量。但是,在Python中不需要私有变量,因为在Python中公开类成员变量并不坏。如果需要封装成员变量,可以在以后使用"@property"进行封装,而不必破坏现有的客户机代码。
在Python中,单个下划线"uu"用于表示方法或变量不被视为类的公共API的一部分,并且API的这一部分可能在不同版本之间发生更改。您可以使用这些方法/变量,但如果使用此类的较新版本,代码可能会中断。
双下划线"uuuu"不表示"私有变量"。您可以使用它来定义变量,这些变量是"类局部的",并且不容易被子类覆盖。它会破坏变量名。
例如:
1 2 3 4 5 6 7
| class A(object):
def __init__(self):
self.__foobar = None # will be automatically mangled to self._A__foobar
class B(A):
def __init__(self):
self.__foobar = 1 # will be automatically mangled to self._B__foobar |
自我。foobar的名字会自动改为自我。在A级中,它被改为自我。在B级中,它被改为自我。因此,每个子类都可以定义自己的变量foobar,而不必覆盖其父变量。但是没有什么可以阻止您访问以双下划线开头的变量。但是,名称管理阻止您意外地调用这个变量/方法。
我强烈建议观看Raymond Hettingers在Pycon 2013上的"Pythons类开发工具包"(应该在YouTube上提供),它给出了一个很好的例子,说明了为什么以及如何使用@property和"_uuuuuuuuuu"实例变量。