是否可以在子类中将公共方法设为私有?我不希望扩展此类的其他类能够调用某些方法.这是一个例子:
class A: def __init__(self): #do something here def method(self): #some code here class B(A): def __init__(self): A.__init__(self) #additional initialization goes here def method(self): #this overrides the method ( and possibly make it private here )
从这一点开始,我不希望任何从B扩展的类能够调用method
.这可能吗 ?
编辑:这是一个"逻辑"的原因是我不希望用户以错误的顺序调用方法.
相反,在这个问题上流行的时尚,也有正当的理由有公共,私有和保护成员之间的区别,无论你是在Python或更传统的面向对象的环境中工作.很多时候,你需要在某种对象专业化水平上为特别冗长的任务开发辅助方法.毋庸置疑,你真的不希望任何子类继承这些方法,因为它们在专门的上下文中没有任何意义,甚至不应该是可见的; 然而它们是可见的,并且它们削弱了标签完成,对象导航器和其他系统软件之类的功能,因为所有不同抽象级别的所有内容都变得扁平化并被抛在一起.请注意,这些编程辅助工具并非易事.如果你是一名学生,他们只是微不足道,因为你正在学习如何,他们喜欢做一百万次同样的事情.
Python历史上以这样的方式开发,由于意识形态惯性和兼容性问题,实现公共/私人区分变得越来越困难.这是明确的事实.每个人都要改变他们一直在做的事情,这将是一件非常令人头疼的问题.因此,我们现在有一百万名Python粉丝,所有人都阅读了相同的一两篇原创文章,明确地确定公共/私人的区别是"unpythonic".这些人由于缺乏批判性思维或对广泛传播的常规做法的公平性,立即利用这个机会吸收了一系列可预测的应用程序 - De Defensione Serpentis--我怀疑这不是来自合理选择的蟒蛇( pythonic方式)但忽略了他们选择不使用的其他语言,不熟练使用,或因工作而无法使用.
正如有人已经说过的,你可以用Python做的最好的效果是产生类似于私有方法的效果,就是在方法名前加上__
(两个下划线).另一方面,实际上,唯一能实现的是在对象中插入一个变形的属性名称__dict__
.例如,假设您有以下类定义:
class Dog(object): def __bark(self): print 'woof'
如果你跑dir(Dog())
,你会看到一个叫做奇怪的成员_Dog__bark
.实际上,存在这种技巧的唯一原因是为了规避我之前描述的问题:即防止超级方法的继承,重载和替换.
希望将来有一些标准化的私人方法实施,当人们意识到组织不需要获得单个细胞复制DNA的方法时,有意识的头脑需要不断弄清楚如何修复其组织和内脏器官.
在Python中没有办法真正做到这一点.相反,它是非语音的.
正如Guido所说,我们都是在这里同意成年人.
这里是Python公开的一切背后哲学的一个很好的总结.
您可以使用单个或双下划线为方法和成员添加前缀.单个下划线暗示"请不要使用我,我应该只使用此类",并且双下划线指示Python编译器使用类名来破坏方法/成员名称; 只要类及其子类不具有相同的名称,方法/成员就可以被视为"私有".
但是,到目前为止,您的要求的解决方案是编写清晰的文档.如果您不希望用户以错误的顺序调用方法,请在文档中说明.
毕竟,即使是C++私有也不是私有的.例如,想想老技巧:
#define private public #include
我很惊讶没有人提到这一点,但在方法名称前加上一个下划线是将其标记为"私有"的正确方法.它当然不是私密的(正如其他答案中所解释的那样),但是你去了.
def _i_am_private(self): """If you call me from a subclass you are a naughty person!"""
Python作为源分发.私有方法的想法很有意义.
想要B
通过隐私问题进行扩展的程序员查看B
源代码,将源代码复制并粘贴method
到子类中C
.
你通过"隐私"获得了什么?您可以期待的最好的方法是让您的潜在客户挫败复制和粘贴.
在最坏的情况下,他们丢弃你的包裹,因为他们无法延长它.
是的,所有开源都以这种或那种方式扩展.您无法预见代码的所有内容和用途.当代码作为源分发时,很难防止将来使用.
请参阅如何保护Python代码?
编辑 "防止白痴"的代码.
首先,python在90%的时间内作为源分发.因此,任何下载,安装,然后拒绝阅读API指南并且无序调用方法的白痴仍有消息来找出问题所在.
我们有三类白痴.
拒绝阅读API指南(或浏览它并忽略相关部分)并尽管有文档而无法调用方法的人.你可以试着把某些东西私有化,但它无济于事,因为它们会做出别的错误 - 并抱怨它.[我不会说出名字,但我和那些似乎花费大量时间调用API不正确的人一起工作过.此外,你会在SO上看到这样的问题.]
您只能使用可以剪切和粘贴的工作代码示例来帮助他们.
那些被API迷惑并且以你能想象的方式调用这些方法的人(有些你不能这样做.)你可以尝试私有化,但他们永远不会得到API.
您只能通过提供工作代码示例来帮助他们; 即使这样,他们也会错误地剪切和粘贴它.
拒绝您的API并希望重写它以使其"白痴证明"的人.
您可以为他们提供工作代码示例,但他们不喜欢您的API并且会坚持重写它.他们会告诉你,你的API很疯狂,他们已经改进了.
你可以让这些人参加一场"白痴"的升级军备竞赛.你把它们放在一起的所有东西都拆开了.
在这一点上,隐私为您做了什么?有些人会拒绝理解它; 有些人对此感到困惑; 有些人想要解决它.
公众怎么样,让那些你称之为"白痴"的人从你的代码中学习?
这可能是一个公平的近似值.词汇范围界定"救援":
#!/usr/bin/env python class Foo(object): def __init__(self, name): self.name = name self.bar() def bar(self): def baz(): print "I'm private" print self.name def quux(): baz() self.quux = quux if __name__ == "__main__": f = Foo("f") f.quux() g = Foo("g") g.quux() f.quux()
打印:
I'm private f I'm private g I'm private f
"一切都必须公开"支持者认为作者试图隐藏用户的有用API.这家伙不想违反毫无疑问的Python法则.他想使用一些方法来定义一个有用的API,并且他想使用其他方法来组织该API的实现.如果两者之间没有分离,那并不意味着作者不是白痴.这意味着作者实际上没有实际定义API.
在Python中,不是将属性或方法标记为私有,它们可以_
作为弱"内部使用"指示符作为前缀,或者__
作为稍微更强的指示符作为前缀.在模块中,名称可能以_
相同的方式加上前缀,您也可以在一个名为变量的变量中放置一系列构成模块公共API的字符串__all__
.
愚蠢的一致性是小脑袋的大人物.
将继承的方法从公共更改为私有会中断继承.具体来说,它打破了is-a关系.
想象一下餐厅课程采用开门公共方法(即晚餐时间,我们希望将前门标志从关闭翻转到打开).现在我们想要一个餐饮课,它将分享餐厅的许多实施细节(他们都需要厨师,厨房,餐具,食品供应商,甚至可能是服务员),但没有用餐区,前门或开门方法.从餐厅继承是一个错误!看起来您需要做的就是将开门方法改为私有,这样就没有人可以使用它了,但是"任何餐饮对象 - 餐厅"都是假的,因为餐厅公共界面的一部分是敞开的.最好通过添加一个新的基类来重构餐厅,然后餐厅和餐饮都来自它.
具有受保护或私有继承概念的语言仅支持实现继承的这种思想,但Python不是其中之一.(在很少的情况下,这些语言也没有用.)通常在寻求非公共继承时,包含(又称"有关系")是更好的路径,甚至可以使属性受到保护或私有.
Python法术受到单一领先下划线和私人双重领导下划线的保护,修改了Triptych答案中提到的"同意成人"哲学.您的类的"危险"属性和方法,例如可能导致数据丢失的属性和方法,应该是非公开的(无论是使其受到保护还是私有受其他因素的影响),公共方法用于提供更简单,更安全的界面.
要使方法类型为私有,您可以命名 - 修改一个方法,如下所示:
class Foo: def __blah(): pass class Bar(Foo): def callBlah(): self.__blah() # will throw an exception
但是,如果他们真的想要,子类仍然可以通过内省找到你的方法.
但Python(通过深思熟虑的设计和选择)没有私人成员的概念.