是否可以在子类中将公共方法设为私有?我不希望扩展此类的其他类能够调用某些方法。这是一个例子:
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
。
这可能吗?
编辑:这是一个“逻辑”原因,我不希望用户以错误的顺序调用方法。
答案 0 :(得分:29)
与流行时尚相比,是合理的理由来区分公共,私人和受保护的成员,无论您是在Python中工作还是在更传统的OOP环境中工作。很多时候,你需要在某种对象专业化水平上为特别冗长的任务开发辅助方法。不用说,你真的不希望任何子类继承这些方法,因为它们在专门的上下文中没有任何意义,甚至不应该是可见的;然而它们是可见的,并且它们削弱了标签完成,对象导航器和其他系统软件之类的功能,因为所有不同抽象级别的所有内容都变得扁平化并被抛在一起。请注意,这些编程辅助工具并非易事。如果你是一名学生,并且因为你正在学习如何而喜欢做一百万次同样的事情,那么它们是微不足道的。
Python历史上以这样的方式开发,由于意识形态的惯性和兼容性问题,实现公共/私人区分变得越来越困难。这是明确的事实。每个人都要改变他们一直在做的事情,这将是一件非常令人头疼的问题。因此,我们现在有一百万名Python粉丝,所有人都阅读了相同的一两篇原创文章,明确地确定公共/私人的区别是“unpythonic”。这些人因缺乏批判性思维或对广泛传播的常规做法的公平性,立即利用这一机会吸收了一系列可预测的应用程序 - De Defensione Serpentis - 我怀疑它不是来自于合理选择通过pythonis (pythonic方式),但忽略其他语言,他们或者选择不使用,不熟练使用,或者因为工作而无法使用。< / p>正如有人已经说过的,你可以用Python做的最好的效果就是使用__
(两个下划线)来预先设置方法名称。另一方面,实际上,唯一能实现的是在对象的__dict__
中插入一个变形的属性名称。例如,假设您有以下类定义:
class Dog(object):
def __bark(self):
print 'woof'
如果您运行dir(Dog())
,您会看到一个名为_Dog__bark
的奇怪成员。实际上,存在这种技巧的唯一原因是为了规避我之前描述的问题:即防止继承,重载和替换超级方法。
希望将来有一些标准化的私人方法实施,当人们意识到组织无法获得单个细胞复制DNA的方法时,有意识的头脑需要不断弄清楚如何修复其组织和内脏。
答案 1 :(得分:27)
在Python中无法真正做到这一点。相反,它是非语音的。
正如Guido所说,我们都是在这里同意成年人。
这是一个很好的summary of the philosophy behind everything in Python being public。
答案 2 :(得分:12)
您可以使用单个或双下划线为方法和成员添加前缀。单个下划线暗示“请不要使用我,我应该只使用此类”,并且双下划线指示Python编译器使用类名来破坏方法/成员名称;只要类及其子类不具有相同的名称,方法/成员就可以被视为“私有”。
但是,到目前为止,您的要求的解决方案是编写清晰的文档。如果您不希望用户以错误的顺序调用方法,请在文档中说明。
毕竟,即使是C ++私有也不是私有的。例如,想想老技巧:
#define private public
#include <module>
答案 3 :(得分:11)
Python作为源分发。私有方法的想法很有意义。
希望扩展B
的程序员受到隐私问题的困扰,查看B
的来源,将method
的源代码复制并粘贴到子类{{1}中}}。
您通过“隐私”获得了什么?您可以期待的最好的方法是让您的潜在客户挫败复制和粘贴。
最糟糕的是,他们丢弃了你的包裹,因为他们无法延长它。
是的,所有开源都以这种或那种方式扩展。您无法预见代码的所有内容和用途。当代码作为源代码分发时,很难防止将来使用。
请参阅How do I protect Python code?
编辑关于“防止白痴”的代码。
首先,python在90%的时间内作为源分发。因此,任何下载,安装,然后拒绝阅读API指南并且无序调用方法的白痴仍然可以找出问题所在。
我们有三类白痴。
拒绝阅读API指南(或浏览并忽略相关部分)并尽管文档无法调用方法的人。你可以试着把某些东西私有化,但它无济于事,因为它们会做出别的错误 - 并抱怨它。 [我不会说出名字,但我和那些似乎花费大量时间调用API不正确的人一起工作过。此外,你会在SO上看到这样的问题。]
您只能使用可以剪切和粘贴的工作代码示例来帮助他们。
人们对API感到困惑,并以你能想象的方式调用方法(有些你不能。)你可以尝试私有化,但他们永远不会得到API。
您只能通过提供工作代码示例来帮助他们;即使这样,他们也会错误地剪切和粘贴它。
拒绝您的API并希望重写它以使其“白痴证明”的人。
您可以为他们提供工作代码示例,但他们不喜欢您的API,并且会坚持重写它。他们会告诉你,你的API很疯狂,他们已经改进了。
你可以让这些人参加一场“白痴”的升级军备竞赛。你把它们放在一起的所有东西都会拆开。
此时,隐私为您做了什么?有些人会拒绝理解它;有些人对此感到困惑;有些人想要解决它。
公众怎么样,让那些你称之为“白痴”的人从你的代码中学习?
答案 4 :(得分:11)
我很惊讶没有人提到这一点,但在方法名称前加上一个下划线是将其标记为“私有”的正确方法。当然,它不是真正的私人(正如其他答案中所解释的那样),但是你去了。
def _i_am_private(self):
"""If you call me from a subclass you are a naughty person!"""
答案 5 :(得分:7)
这可能是一个公平的近似值。词汇范围确定“救援”:
#!/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
答案 6 :(得分:7)
“一切都必须公开”支持者认为作者试图隐藏用户的有用API。这家伙不想违反毫无疑问的Python法则。他想使用一些方法来定义一个有用的API,并且他想使用其他方法来组织该API的实现。如果两者之间没有分离,那并不意味着作者不是白痴。这意味着作者实在太懒,无法实际定义API。
在Python中,不是将属性或方法标记为私有,它们可能以_
为前缀作为弱“内部使用”指示符,或者以__
为前缀稍微强一些。在模块中,名称可能以相同的方式以_
为前缀,您也可以在名为__all__
的变量中放置构成模块公共API的字符串序列。
愚蠢的一致性是小脑袋的大人物。
答案 7 :(得分:6)
将继承的方法从公共更改为私有中断继承。具体来说,它打破了is-a关系。
想象一下餐厅课程采用开门式公共方法(即晚餐时间,我们希望将前门标志从关闭翻转到打开状态)。现在我们想要一个餐饮课,它将分享餐厅的许多实施细节(他们都需要厨师,厨房,餐具,食品供应商,甚至可能是服务员),但没有用餐区,前门或开门方法。从餐厅继承是一个错误!看起来您需要做的就是将开门方法改为私有,这样就没有人可以使用它了,但是“任何餐饮对象 - 餐厅”都是假的,因为餐厅公共界面的一部分是敞开的。最好通过添加一个新的基类来重构餐厅,然后餐厅和餐饮都来自它。
具有受保护或私有继承概念的语言仅支持实现继承的这种思想,但Python不是其中之一。 (除了很少,这些语言也没用。)通常在寻求非公共继承时,包含(又称“有关系”)是更好的路径,你甚至可以使属性受到保护或私有。
Python法术受到单一前导下划线和私人双重下划线的保护,修改了Triptych答案中提到的“同意成人”哲学。您班级的“危险”属性和方法,例如:可能导致数据丢失的,应该是非公开的(无论是使其受到保护还是私有受其他因素影响),公共方法用于提供更简单,更安全的界面。
答案 8 :(得分:5)
要使方法排序为私有,您可以命名 - 修改类似的方法:
class Foo:
def __blah():
pass
class Bar(Foo):
def callBlah():
self.__blah() # will throw an exception
但是,如果他们真的想要,子类仍然可以通过内省找到你的方法。
但是Python(通过深思熟虑的设计和选择)没有私人成员的概念。
答案 9 :(得分:1)
即使在同意的成年人中,也有理由不想将方法暴露给派生类。问题是,我可以拥有像Parent这样的层次结构&gt;子级,用户可以从父级或子级派生但不暴露任何私有或受保护的方法。在下面的示例中,Child显式重载Parent .__ private而不公开它。
class Parent(object):
def __private(self):
print 'Parent'
def go(self):
self.__private()
class Child(Parent):
def __init__(self):
Parent.__init__(self)
self._Parent__private = self.__private
def __private(self):
print 'Child'
答案 10 :(得分:1)
class MyClass(object):
def _prtectedfunc(self):
pass # with one undersocre
def __privatefunc(self):
pass # with two undersocre
http://linuxwell.com/2011/07/21/private-protected-and-public-in-python/
答案 11 :(得分:0)
此主题中有很多好的答案,但是从实用的角度来看,这是一些自以为是的答案:
您确实需要从公共API隐藏(也称为文档)低级变量和方法。因此,请始终在这些成员上附加_或__。更大的问题:应该是_还是__?纯粹的OOP观点是始终将__附加到私有成员上,并将_附加到“受保护的”方法上(即,可访问的,可从派生类覆盖的方法)。 __确保派生类无法覆盖它。另一方面,它也使得很难使用setattr
,可测试性和可读性之类的东西。
我个人的观点(以及Google's style guide)是尽可能避免使用__,并为私人成员使用_。
但是受保护成员呢?我们如何告诉图书馆用户他们必须/应该重写什么?在这里,我不希望对受保护成员使用下划线,而应依靠文档字符串注释以及基类中的@abstractmethod
(可选)。这里的一个优点是受保护的成员不会从各种文档生成器中删除。
答案 12 :(得分:0)
此主题中有很多好的答案,但是从实用的角度来看,这是一些自以为是的答案:
您要做需要避免来自公共API,智能感知,文档,import *
等的私人成员。因此,请始终在这些成员上附加_或__。
一个大问题:应该是_还是__?纯粹的OOP观点是始终将__附加到私有成员上,并将_附加到受保护的方法上。 __确实进行了名称修饰,并使其难以使用诸如setattrib,测试框架之类的内容,并降低了可读性。因此,我个人的观点是尽可能避免使用__,并将_用于私有成员。
但是我们希望派生类使用但不用作公共API的受保护成员呢?我的偏好是完全不使用下划线。这使这些成员可以获取公共文档。然后,我们依靠docstring告诉用户这些是受保护的成员,如下所示:
class Class1:
def _private1():
pass
def protected1():
"""(for derived classes) Does XYZ."""
pass
def public1()
pass