为什么 Python 的“私有”方法实际上并不是私有的?

2024-12-11 08:47:00
admin
原创
128
摘要:问题描述:Python 允许我们在类中创建“私有”方法和变量,只需在名称前面添加双下划线即可,如下所示:__myPrivateMethod()。那么,如何解释这一点呢?>>>> class MyClass: ... def myPublicMethod(self): ... ...

问题描述:

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 "<stdin>", line 1, in <module>
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 "<stdin>", line 1, in <module>
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}

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

解决方案 2:

当我第一次从 Java 转到 Python 时,我讨厌这一点。它吓死我了。

如今这也许就是我最喜欢Python 的一个原因了。

我喜欢在一个平台上,人们相互信任,不觉得需要在代码周围建立坚不可摧的墙壁。在强封装语言中,如果 API 有错误,并且您已经弄清楚了问题所在,但您可能仍然无法解决它,因为所需的方法是私有的。在 Python 中,态度是:“当然”。如果您认为您了解情况,也许您甚至已经阅读过它,那么我们只能说“祝你好运!”。

请记住,封装与“安全”或阻止孩子乱动草坪没有任何关系。它只是另一种使代码库更易于理解的模式。

解决方案 3:

私有函数示例

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 beginning
            matched = re.match( '^self.', function_call)
            if not matched:
                print 'This is a private function. Go away.'
                return
        except:
            print 'This is a private function. Go away.'
            return

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

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

### End ###

解决方案 4:

摘自《深入 Python》,3.9。私有函数

严格来说,私有方法可以在类外部访问,只是不容易访问。Python 中没有任何东西是真正私有的;在内部,私有方法和属性的名称被动态地破坏和恢复,使它们看起来无法通过给定的名称访问。您可以通过名称 _MP3FileInfo__parse 访问 MP3FileInfo 类的 __parse 方法。承认这很有趣,然后保证永远不会在实际代码中这样做。私有方法是私有的,这是有原因的,但与 Python 中的许多其他东西一样,它们的私有性最终是一种惯例,而不是强制。

解决方案 5:

常用的短语是“我们都是成年人”。通过在前面添加单下划线(不暴露)或双下划线(隐藏),您是在告诉类的用户,您希望该成员以某种方式“私有”。但是,您相信其他人都会负责任地行事并尊重这一点,除非他们有令人信服的理由不这样做(例如,调试器和代码完成)。

如果你确实需要一些私有的东西,那么你可以在扩展中实现它(例如,在CPython中使用 C 语言)。然而,在大多数情况下,你只是学习Pythonic的做事方式。

解决方案 6:

这并不意味着你绝对无法绕过任何语言中成员的隐私性(C++ 中的指针算法和 .NET/Java 中的反射)。

关键在于,如果您意外尝试调用私有方法,则会出错。但如果您想搬起石头砸自己的脚,那就去做吧。

您不会尝试通过 OO 封装来保护您的资料吧?

解决方案 7:

重要提示:

任何形式__name(至少两个前导下划线,至多一个尾随下划线)的标识符都将公开替换为_classname__name,其中classname是去掉前导下划线的当前类名。

因此,__name不能直接访问,但可以作为访问_classname__name

这并不意味着您可以保护您的私人数据,因为通过更改变量的名称可以轻松访问它。

来源:

官方文档中的“私有变量”部分:https://docs.python.org/3/tutorial/classes.html#tut-private

例子

class Cat:
    def __init__(self, name='unnamed'):
        self.name = name
    def __print_my_name(self):
        print(self.name)
        
        
tom = Cat()
tom.__print_my_name() #Error
tom._Cat__print_my_name() #Prints name

解决方案 8:

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

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

from bar import *

然而,这只是惯例,而不是语言约束。这些不是私有属性;任何导入器都可以引用和操作它们。有人认为,正因为如此,Python 无法实现真正​​的封装。

解决方案 9:

这只是语言设计选择之一。从某种程度上来说,它们是合理的。它们让你需要费很大力气才能尝试调用该方法,如果你真的那么需要它,那你一定有很好的理由!

调试挂钩和测试被认为是可能的应用程序,当然要负责任地使用。

解决方案 10:

关于私有方法和属性最重要的问题是告诉开发人员不要在类外调用它,这就是封装。人们可能会误解封装与安全性。当人们故意使用您提到的语法(如下)时,您不需要封装。

obj._MyClass__myPrivateMethod()

我已经从 C# 迁移过来,一开始对我来说也很奇怪,但过了一段时间后,我发现只有 Python 代码设计人员对 OOP 的看法不同。

解决方案 11:

对于 Python 3.4 来说,行为如下:

>>> class Foo:
        def __init__(self):
                pass
        def __privateMethod(self):
                return 3
        def invoke(self):
                return self.__privateMethod()


>>> help(Foo)
Help on class Foo in module __main__:

class Foo(builtins.object)
 |  Methods defined here:
 |
 |  __init__(self)
 |
 |  invoke(self)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

 >>> f = Foo()
 >>> f.invoke()
 3
 >>> f.__privateMethod()
 Traceback (most recent call last):
   File "<pyshell#47>", line 1, in <module>
     f.__privateMethod()
 AttributeError: 'Foo' object has no attribute '__privateMethod'

来自9.6. 私有变量

请注意,修改规则主要是为了避免意外;仍然可以访问或修改被视为私有的变量。这甚至在特殊情况下也很有用,例如在调试器中。

解决方案 12:

为什么 Python 的“私有”方法实际上并不是私有的?

据我了解,它们无法保密。如何强制执行隐私?

显而易见的答案是“私有成员只能通过 ”访问self,但这样做不行——self在 Python 中并不特殊。它只不过是函数第一个参数的常用名称。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用