当前位置:  开发笔记 > 编程语言 > 正文

为什么Python的"私有"方法实际上不是私有的?

如何解决《为什么Python的"私有"方法实际上不是私有的?》经验,为你挑选了9个好方法。

Python使我们能够通过在名称前加上双下划线来在类中创建"私有"方法和变量,如下所示:__myPrivateMethod().那么,如何解释这一点呢

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
... 
>>> obj = MyClass()
>>> obj.myPublicMethod()
public method
>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: MyClass instance has no attribute '__myPrivateMethod'
>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']
>>> obj._MyClass__myPrivateMethod()
this is private!!

这是怎么回事?!

我会对那些没有那么做的人解释一下.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
... 
>>> obj = MyClass()

我在那里做的是使用公共方法和私有方法创建一个类并实例化它.

接下来,我称之为公共方法.

>>> obj.myPublicMethod()
public method

接下来,我尝试调用它的私有方法.

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

这里的一切都很好看; 我们无法称呼它.事实上,它是"私人的".嗯,实际上并非如此.在对象上运行dir()会显示一个新的神奇方法,即python为所有"私有"方法创建神奇的方法.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

这个新方法的名称始终是下划线,后跟类名,后跟方法名.

>>> obj._MyClass__myPrivateMethod()
this is private!!

封装如此之多,嗯?

无论如何,我总是听说Python不支持封装,所以为什么要试试呢?是什么赋予了?



1> 小智..:

名称加扰用于确保子类不会意外地覆盖其超类的私有方法和属性.它的目的不是为了防止来自外部的故意访问.

例如:

>>> class Foo(object):
...     def __init__(self):
...         self.__baz = 42
...     def foo(self):
...         print self.__baz
...     
>>> class Bar(Foo):
...     def __init__(self):
...         super(Bar, self).__init__()
...         self.__baz = 21
...     def bar(self):
...         print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}

当然,如果两个不同的类具有相同的名称,它就会崩溃.


对于我们这些懒得滚动/搜索的人:[第9.6节直接链接](http://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references)
[Guido回答了这个问题](https://plus.google.com/115212051037621986145/posts/7wpbQTPRWft) - "使(几乎)所有可被发现的主要原因是调试:调试时经常需要突破抽象" - 我将其添加为评论因为为时已晚 - 答案太多了.
http://docs.python.org/2/tutorial/classes.html.部分:9.6关于私有变量和类本地引用.
您应该放置一个下划线来指定该变量应被视为私有.同样,这并不妨碍某人实际访问它.

2> 小智..:

私有功能的例子

import re
import inspect

class MyClass :

    def __init__(self) :
        pass

    def private_function ( self ) :
        try :
            function_call = inspect.stack()[1][4][0].strip()

            # See if the function_call has "self." in the begining
            matched = re.match( '^self\.', function_call )
            if not matched :
                print 'This is Private Function, Go Away'
                return
        except :
            print 'This is Private Function, Go Away'
            return

        # This is the real Function, only accessible inside class #
        print 'Hey, Welcome in to function'

    def public_function ( self ) :
        # i can call private function from inside the class
        self.private_function()

### End ###


以防万一不清楚:*从不*在实际代码中执行此操作;)
`inspect.stack()[1] [4] [0] .strip()`< - 那些1,4和0幻数是什么?
`self = MyClass()``self.private_function()`.:D当然它在类中不起作用,但你只需要定义一个自定义函数:`def foo(self):self.private_function()`
@ThorSummoner或只是`function_call.startswith('self.')`.
通过执行`self = MyClass();可以很容易地将其击败.self.private_function()`并且在方法中使用`x = self.private_function()`调用时失败.
`self`只是一个惯例.可以为第一个参数使用不同的名称
我不打扰加载正则表达式来测试一个`/^.../`表达式,节省一些时间并使用`0 == function_call.index('self.')
@arun,为什么1 4 0?
@Shuklaswag这使得您的代码更难以使用,因为它会阻碍任何人调试它.试图用不必要的聪明来绕过语言规则很少会很好地结束.(它也没有真正阻止对该函数的公共调用).

3> Thomas Ahle..:

当我第一次从Java转向Python时,我讨厌这个.它让我害怕死亡.

今天它可能只是我最喜欢Python 的一件事.

我喜欢在一个平台上,在这个平台上,人们相互信任,并且不觉得他们需要在代码周围建立难以穿透的墙.在强封装的语言中,如果API有错误,并且您已经找出问题所在,那么您可能仍然无法解决它,因为所需的方法是私有的.在Python中,态度是:"确定".如果你认为你了解情况,也许你甚至已经阅读过,那么我们所能说的就是"祝你好运!".

请记住,封装甚至与"安全"无关,或者让孩子远离草坪.它只是应该用于使代码库更容易理解的另一种模式.


@CamJackson Javascript就是你的例子?唯一广泛使用的语言,它具有基于prototybe的继承和支持函数式编程的语言?我认为JS比大多数其他语言更难学,因为它需要传统OOP的几个正交步骤.这不是为了防止白痴写JS,他们只是不知道它;)
API实际上是一个非常好的例子,说明为什么封装很重要以及何时首选私有方法.一个旨在私有的方法可能会在任何后续新版本中消失,更改签名或最糟糕的所有更改行为 - 所有这些都不会发出警告.您的智能成人团队成员是否真的记得她在您更新后的一年内访问了一个有意成为私人的方法?她甚至会在那里工作吗?
Java和C++中的实施并不是因为Java在Python的同时不信任用户.这是因为编译器和/或vm在处理它的业务如何知道这些信息时可以做出各种假设,例如C++可以通过使用常规的旧C调用而不是虚拟调用来跳过整个间接层,并且当你从事高性能或高精度的工作时很重要.Python本质上无法真正充分利用信息而不会影响其动态性.两种语言都针对不同的东西,所以两者都不是"错误的"
Java有Method.setAccessible和Field.setAccessible.还吓人?
我不同意这种说法。在生产代码中,我极有可能永远不会使用具有导致我更改公共成员使其“起作用”的错误的API。API应该可以使用。如果没有,我将提交错误报告或自行创建相同的API。我不喜欢这种哲学,我也不是很喜欢Python,尽管它的语法使用以下语言编写较小的脚本变得很有趣。

4> xsl..:

来自http://www.faqs.org/docs/diveintopython/fileinfo_private.html

严格来说,私人方法可以在课堂外访问,但不容易访问.Python中没有任何东西是真正私有的; 在内部,私有方法和属性的名称在运行中被破坏和解开,使它们看起来无法通过给定的名称访问.您可以通过名称_MP3FileInfo__parse访问MP3FileInfo类的__parse方法.承认这很有趣,然后承诺永远不会在真正的代码中做到这一点.私有方法是私有的,但与Python中的许多其他东西一样,它们的私有性最终是一个惯例,而不是力.


或者像Guido van Rossum所说:"我们都是成年人."
-1:这是错的.双重下划线绝不是首先用作私人的.以下Alya的答案告诉了名称修改语法的真实意图.真正的约定是单个下划线.
只尝试一个下划线,你会看到你得到的结果.@nosklo

5> Tony Meyer..:

常用的短语是"我们都是在这里同意成年人".通过预先添加单个下划线(不暴露)或双下划线(隐藏),您告诉您的类的用户您希望该成员以某种方式"私有".但是,除非他们有令人信服的理由(例如调试器,代码完成),否则你相信其他所有人都要负责任并尊重这一点.

如果你真的必须拥有私有的东西,那么你可以在扩展中实现它(例如在CP中用于CPython).但是,在大多数情况下,您只需学习Pythonic的做事方式.


没有"受保护"的变量比"私人"更多.如果要访问以下划线开头的属性,您可以这样做(但请注意,作者不鼓励这样做).如果你必须访问以双下划线开头的属性,你可以自己修改名称,但你几乎肯定不想这样做.

6> Maximilian..:

这并不像你绝对不能用任何语言来解决成员的私密性(C++中的指针算术,.NET/Java中的思考).

关键是如果您尝试偶然调用私有方法,则会出现错误.但如果你想用脚射击自己,那就去做吧.

编辑:你没有尝试通过OO封装来保护你的东西,对吗?


在Java中,您实际上可以通过封装来保护内容,但这需要您智能并在SecurityManager中运行不受信任的代码,并且要非常小心.甚至甲骨文有时也会弄错.
一点也不。我只是想指出,给开发人员一种简单而神奇的访问“私有”属性的方式是奇怪的。
是的,我只是想说明这一点。将其设为私有只是通过使编译器抱怨来表明“您不应该直接访问它”。但是,一个人真的想做到这一点。但是,是的,在Python中比在大多数其他语言中更容易。

7> Nickolay..:

class.__stuff命名约定可以让程序员知道他是不是要访问__stuff外部.名称错误使得任何人都不可能偶然做到这一点.

没错,你仍然可以解决这个问题,它比其他语言更容易(BTW也允许你这样做),但如果他关心封装,没有Python程序员会这样做.



8> ctcherry..:

这只是其中一种语言设计选择.在某种程度上,他们是合理的.他们制作它所以你需要走得很远,试着调用这个方法,如果你真的非常需要它,你必须有一个很好的理由!

调试钩子和测试作为可能的应用程序浮现在脑海中,当然负责任地使用.



9> Ross..:

当模块属性名称以单个下划线(例如_foo)开头时,存在类似的行为.

使用该from*方法时,不会将这样命名的模块属性复制到导入模块中,例如:

from bar import *

但是,这是一种约定而不是语言约束.这些不是私人属性; 它们可以被任何进口商引用和操纵.有人认为,由于这个原因,Python无法实现真正​​的封装.

推荐阅读
ERIK又
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有