标签归档:encapsulation

了解__getattr__和__getattribute__之间的区别

问题:了解__getattr__和__getattribute__之间的区别

我试图理解上的差异之间__getattr____getattribute__,但是,我在它失败。

堆栈溢出问题的答案与vs 之间的区别是__getattr____getattribute__

__getattribute__在查看对象的实际属性之前调用,因此很难正确实现。您可以非常轻松地进行无限递归。

我完全不知道那是什么意思。

然后继续说:

您几乎可以肯定想要__getattr__

为什么?

我读到,如果__getattribute__失败,__getattr__则称为。那么,为什么有两种不同的方法做同样的事情呢?如果我的代码实现了新样式类,我应该使用什么?

我正在寻找一些代码示例来清除此问题。我已尽我所能搜索Google,但是我发现的答案并未彻底讨论该问题。

如果有任何文档,我准备阅读。

I am trying to understand the difference between __getattr__ and __getattribute__, however, I am failing at it.

The answer to the Stack Overflow question Difference between __getattr__ vs __getattribute__ says:

__getattribute__ is invoked before looking at the actual attributes on the object, and so can be tricky to implement correctly. You can end up in infinite recursions very easily.

I have absolutely no idea what that means.

Then it goes on to say:

You almost certainly want __getattr__.

Why?

I read that if __getattribute__ fails, __getattr__ is called. So why are there two different methods doing the same thing? If my code implements the new style classes, what should I use?

I am looking for some code examples to clear this question. I have Googled to best of my ability, but the answers that I found don’t discuss the problem thoroughly.

If there is any documentation, I am ready to read that.


回答 0

首先了解一些基础知识。

对于对象,您需要处理其属性。通常我们会这么做instance.attribute。有时我们需要更多的控制权(当我们事先不知道属性名称时)。

例如,instance.attribute将变为getattr(instance, attribute_name)。使用此模型,我们可以通过提供attribute_name作为字符串来获取属性。

用于 __getattr__

您还可以告诉类如何处理它未显式管理的属性,并通过__getattr__方法进行操作。

每当您请求尚未定义的属性时,Python都会调用此方法,因此您可以定义该方法。

一个经典的用例:

class A(dict):
    def __getattr__(self, name):
       return self[name]
a = A()
# Now a.somekey will give a['somekey']

注意事项和使用 __getattribute__

如果您需要捕获每个属性(无论是否存在),请使用__getattribute__。不同之处在于,__getattr__仅调用实际上不存在的属性。如果您直接设置属性,则引用该属性将无需调用即可检索它__getattr__

__getattribute__ 一直被称为。

Some basics first.

With objects, you need to deal with its attributes. Ordinarily we do instance.attribute. Sometimes we need more control (when we do not know the name of the attribute in advance).

For example, instance.attribute would become getattr(instance, attribute_name). Using this model, we can get the attribute by supplying the attribute_name as a string.

Use of __getattr__

You can also tell a class how to deal with attributes which it doesn’t explicitly manage and do that via __getattr__ method.

Python will call this method whenever you request an attribute that hasn’t already been defined, so you can define what to do with it.

A classic use case:

class A(dict):
    def __getattr__(self, name):
       return self[name]
a = A()
# Now a.somekey will give a['somekey']

Caveats and use of __getattribute__

If you need to catch every attribute regardless whether it exists or not, use __getattribute__ instead. The difference is that __getattr__ only gets called for attributes that don’t actually exist. If you set an attribute directly, referencing that attribute will retrieve it without calling __getattr__.

__getattribute__ is called all the times.


回答 1

__getattribute__ 每当发生属性访问时都会调用。

class Foo(object):
    def __init__(self, a):
        self.a = 1

    def __getattribute__(self, attr):
        try:
            return self.__dict__[attr]
        except KeyError:
            return 'default'
f = Foo(1)
f.a

这将导致无限递归。罪魁祸首是排队return self.__dict__[attr]。让我们假装(这与事实很接近)所有属性都存储在self.__dict__名称中并可用。线

f.a

尝试访问的a属性f。这叫f.__getattribute__('a')__getattribute__然后尝试加载self.__dict____dict__是的属性,self == f因此python调用f.__getattribute__('__dict__')再次尝试访问属性'__dict__‘。这是无限递归。

如果__getattr__曾经使用过,那么

  1. 它永远不会运行,因为f具有a属性。
  2. 如果它已经运行((假设您要f.b)),则不会调用__dict__它,因为它已经存在,并且__getattr__仅当所有其他查找属性的方法均失败时才被调用。

编写上述类的“正确”方法__getattribute__

class Foo(object):
    # Same __init__

    def __getattribute__(self, attr):
        return super(Foo, self).__getattribute__(attr)

super(Foo, self).__getattribute__(attr)__getattribute__“最近”超类的方法(self通常是该类的“方法解析顺序”中的下一个类)绑定到当前对象,然后调用它并让其完成工作。

通过使用__getattr__python 可以在没有找到属性之前将其正常处理,从而避免了所有这些麻烦。到那时,Python将控制权交给您的__getattr__方法,并让它提出一些建议。

还值得注意的是,您可以使用进行无限递归__getattr__

class Foo(object):
    def __getattr__(self, attr):
        return self.attr

我将把它留作练习。

__getattribute__ is called whenever an attribute access occurs.

class Foo(object):
    def __init__(self, a):
        self.a = 1

    def __getattribute__(self, attr):
        try:
            return self.__dict__[attr]
        except KeyError:
            return 'default'
f = Foo(1)
f.a

This will cause infinite recursion. The culprit here is the line return self.__dict__[attr]. Let’s pretend (It’s close enough to the truth) that all attributes are stored in self.__dict__ and available by their name. The line

f.a

attempts to access the a attribute of f. This calls f.__getattribute__('a'). __getattribute__ then tries to load self.__dict__. __dict__ is an attribute of self == f and so python calls f.__getattribute__('__dict__') which again tries to access the attribute '__dict__‘. This is infinite recursion.

If __getattr__ had been used instead then

  1. It never would have run because f has an a attribute.
  2. If it had run, (let’s say that you asked for f.b) then it would not have been called to find __dict__ because it’s already there and __getattr__ is invoked only if all other methods of finding the attribute have failed.

The ‘correct’ way to write the above class using __getattribute__ is

class Foo(object):
    # Same __init__

    def __getattribute__(self, attr):
        return super(Foo, self).__getattribute__(attr)

super(Foo, self).__getattribute__(attr) binds the __getattribute__ method of the ‘nearest’ superclass (formally, the next class in the class’s Method Resolution Order, or MRO) to the current object self and then calls it and lets that do the work.

All of this trouble is avoided by using __getattr__ which lets Python do it’s normal thing until an attribute isn’t found. At that point, Python hands control over to your __getattr__ method and lets it come up with something.

It’s also worth noting that you can run into infinite recursion with __getattr__.

class Foo(object):
    def __getattr__(self, attr):
        return self.attr

I’ll leave that one as an exercise.


回答 2

我认为其他的答案做了解释之间的差异的一个伟大的工作__getattr____getattribute__,但有一点可能没有明确的是,为什么你会想使用__getattribute__。有趣的__getattribute__是,它本质上允许您在访问类时重载点。这使您可以自定义如何在较低级别访问属性。例如,假设我要定义一个类,其中所有仅带有自变量的方法都被视为属性:

# prop.py
import inspect

class PropClass(object):
    def __getattribute__(self, attr):
        val = super(PropClass, self).__getattribute__(attr)
        if callable(val):
            argcount = len(inspect.getargspec(val).args)
            # Account for self
            if argcount == 1:
                return val()
            else:
                return val
        else:
            return val

从交互式解释器中:

>>> import prop
>>> class A(prop.PropClass):
...     def f(self):
...             return 1
... 
>>> a = A()
>>> a.f
1

当然,这是一个愚蠢的示例,您可能永远也不想这样做,但是它向您展示了从覆盖获得的强大功能__getattribute__

I think the other answers have done a great job of explaining the difference between __getattr__ and __getattribute__, but one thing that might not be clear is why you would want to use __getattribute__. The cool thing about __getattribute__ is that it essentially allows you to overload the dot when accessing a class. This allows you to customize how attributes are accessed at a low level. For instance, suppose I want to define a class where all methods that only take a self argument are treated as properties:

# prop.py
import inspect

class PropClass(object):
    def __getattribute__(self, attr):
        val = super(PropClass, self).__getattribute__(attr)
        if callable(val):
            argcount = len(inspect.getargspec(val).args)
            # Account for self
            if argcount == 1:
                return val()
            else:
                return val
        else:
            return val

And from the interactive interpreter:

>>> import prop
>>> class A(prop.PropClass):
...     def f(self):
...             return 1
... 
>>> a = A()
>>> a.f
1

Of course this is a silly example and you probably wouldn’t ever want to do this, but it shows you the power you can get from overriding __getattribute__.


回答 3

我经历了别人的出色解释。但是,我从此博客Python Magic Methods和__getattr__找到了一个简单的答案。以下所有都是从那里开始的。

使用__getattr__magic方法,我们可以拦截不存在的属性查找并做一些事情,以确保它不会失败:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.does_not_exist # 'DOES_NOT_EXIST'
d.what_about_this_one  # 'WHAT_ABOUT_THIS_ONE'

但是,如果该属性确实存在,__getattr__将不会被调用:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.value = "Python"
print(d.value)  # "Python"

__getattribute__与相似__getattr__,但重要的区别是__getattribute__将拦截每个属性查找,而属性是否存在无关紧要。

class Dummy(object):

    def __getattribute__(self, attr):
        return 'YOU SEE ME?'

d = Dummy()
d.value = "Python"
print(d.value)  # "YOU SEE ME?"

在该示例中,d对象已经具有属性值。但是,当我们尝试访问它时,没有得到原始的期望值(“ Python”);我们只是得到任何__getattribute__回报。这意味着我们实际上失去了value属性;它已经变得“无法到达”。

I have gone through other’s excellent explanation. However, I found a simple answer from this blog Python Magic Methods and __getattr__. All the following are from there.

Using the __getattr__ magic method, we can intercept that inexistent attribute lookup and do something so it doesn’t fail:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.does_not_exist # 'DOES_NOT_EXIST'
d.what_about_this_one  # 'WHAT_ABOUT_THIS_ONE'

But if the attribute does exist, __getattr__ won’t be invoked:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.value = "Python"
print(d.value)  # "Python"

__getattribute__ is similar to __getattr__, with the important difference that __getattribute__ will intercept EVERY attribute lookup, doesn’t matter if the attribute exists or not.

class Dummy(object):

    def __getattribute__(self, attr):
        return 'YOU SEE ME?'

d = Dummy()
d.value = "Python"
print(d.value)  # "YOU SEE ME?"

In that example, the d object already has an attribute value. But when we try to access it, we don’t get the original expected value (“Python”); we’re just getting whatever __getattribute__ returned. It means that we’ve virtually lost the value attribute; it has become “unreachable”.


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

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

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()

我在那里所做的是创建一个具有公共方法和私有方法的类,并将其实例化。

接下来,我将其称为public方法。

>>> 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不支持封装,那么为什么还要尝试呢?是什么赋予了?

Python gives us the ability to create ‘private’ methods and variables within a class by prepending double underscores to the name, like this: __myPrivateMethod(). How, then, can one explain this

>>> 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!!

What’s the deal?!

I’ll explain this a little for those who didn’t quite get that.

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

What I did there is create a class with a public method and a private method and instantiate it.

Next, I call its public method.

>>> obj.myPublicMethod()
public method

Next, I try and call its private method.

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

Everything looks good here; we’re unable to call it. It is, in fact, ‘private’. Well, actually it isn’t. Running dir() on the object reveals a new magical method that python creates magically for all of your ‘private’ methods.

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

This new method’s name is always an underscore, followed by the class name, followed by the method name.

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

So much for encapsulation, eh?

In any case, I’d always heard Python doesn’t support encapsulation, so why even try? What gives?


回答 0

名称加扰用于确保子类不会意外覆盖其超类的私有方法和属性。它并非旨在防止从外部故意访问。

例如:

>>> 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}

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

The name scrambling is used to ensure that subclasses don’t accidentally override the private methods and attributes of their superclasses. It’s not designed to prevent deliberate access from outside.

For example:

>>> 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}

Of course, it breaks down if two different classes have the same name.


回答 1

私有功能的例子

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 ###

Example of private function

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 ###

回答 2

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

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

我喜欢在一个平台上,人们可以互相信任,而不必觉得自己需要围绕其代码构建坚不可摧的墙。在高度封装的语言中,如果API有错误,并且您已找出问题所在,则可能仍无法解决它,因为所需的方法是私有的。在Python中,态度是:“确定”。如果您认为自己了解这种情况,也许您甚至已经读过它,那么我们只能说“祝您好运!”。

请记住,封装与“安全性”或使孩子远离草坪之间的关系不大。这只是使代码库更易于理解的另一种模式。

When I first came from Java to Python I hated this. It scared me to death.

Today it might just be the one thing I love most about Python.

I love being on a platform, where people trust each other and don’t feel like they need to build impenetrable walls around their code. In strongly encapsulated languages, if an API has a bug, and you have figured out what goes wrong, you may still be unable to work around it because the needed method is private. In Python the attitude is: “sure”. If you think you understand the situation, perhaps you have even read it, then all we can say is “good luck!”.

Remember, encapsulation is not even weakly related to “security”, or keeping the kids off the lawn. It is just another pattern that should be used to make a code base easier to understand.


回答 3

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

严格来说,私有方法可以在其类之外访问,只是不容易访问。Python中没有什么是真正私有的。在内部,私有方法和属性的名称会被随意修改和修改,以使它们的名称看起来不可访问。您可以通过名称_MP3FileInfo__parse访问MP3FileInfo类的__parse方法。承认这很有趣,然后保证永远不要在真实代码中做到这一点。出于某种原因,私有方法是私有的,但是与Python中的许多其他事物一样,私有方法最终是约定俗成的问题,而不是强制性的问题。

From http://www.faqs.org/docs/diveintopython/fileinfo_private.html

Strictly speaking, private methods are accessible outside their class, just not easily accessible. Nothing in Python is truly private; internally, the names of private methods and attributes are mangled and unmangled on the fly to make them seem inaccessible by their given names. You can access the __parse method of the MP3FileInfo class by the name _MP3FileInfo__parse. Acknowledge that this is interesting, then promise to never, ever do it in real code. Private methods are private for a reason, but like many other things in Python, their privateness is ultimately a matter of convention, not force.


回答 4

常用的短语是“我们在这里都是成年人”。通过在单个下划线(不要暴露)或双下划线(隐藏)前面加上,可以告诉Class用户您希望该成员以某种方式成为“私有”成员。但是,除非其他人有充分的理由不这样做(例如,调试器,代码完成),否则您将信任其他所有人的行为负责并尊重。

如果您确实必须拥有私有的内容,则可以在扩展中实现它(例如,在C for CPython中)。但是,在大多数情况下,您只是学习Python的做事方式。

The phrase commonly used is “we’re all consenting adults here”. By prepending a single underscore (don’t expose) or double underscore (hide), you’re telling the user of your class that you intend the member to be ‘private’ in some way. However, you’re trusting everyone else to behave responsibly and respect that, unless they have a compelling reason not to (e.g. debuggers, code completion).

If you truly must have something that is private, then you can implement it in an extension (e.g. in C for CPython). In most cases, however, you simply learn the Pythonic way of doing things.


回答 5

并不是说您绝对不能绕开任何语言的成员私有性(C ++中的指针算术,.NET / Java中的反射)。

关键是,如果您尝试偶然调用私有方法,则会出错。但是,如果您想用脚射击自己,那就继续吧。

编辑:您不会尝试通过OO封装来保护您的东西,是吗?

It’s not like you absolutly can’t get around privateness of members in any language (pointer arithmetics in C++, Reflections in .NET/Java).

The point is that you get an error if you try to call the private method by accident. But if you want to shoot yourself in the foot, go ahead and do it.

Edit: You don’t try to secure your stuff by OO-encapsulation, do you?


回答 6

class.__stuff命名约定可以让程序员知道他是不是要访问__stuff外部。改名这个名字使任何人都不太可能偶然地这样做。

没错,您仍然可以解决此问题,它甚至比其他语言还容易(顺便说一句,BTW也允许您这样做),但是如果Python程序员关心封装,那么他将不会这样做。

The class.__stuff naming convention lets the programmer know he isn’t meant to access __stuff from outside. The name mangling makes it unlikely anyone will do it by accident.

True, you still can work around this, it’s even easier than in other languages (which BTW also let you do this), but no Python programmer would do this if he cares about encapsulation.


回答 7

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

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

from bar import *

但是,这是约定,不是语言限制。这些不是私有属性。它们可以被任何进口商引用和操纵。有人认为,因此,Python无法实现真正​​的封装。

Similar behavior exists when module attribute names begin with a single underscore (e.g. _foo).

Module attributes named as such will not be copied into an importing module when using the from* method, e.g.:

from bar import *

However, this is a convention and not a language constraint. These are not private attributes; they can be referenced and manipulated by any importer. Some argue that because of this, Python can not implement true encapsulation.


回答 8

这只是这些语言设计选择之一。在某种程度上,它们是合理的。他们做到了,所以您需要走很长的路才能尝试调用该方法,如果真的很需要它,则必须有充分的理由!

我想到了调试挂钩和测试作为可能的应用程序,它们当然是负责任地使用的。

It’s just one of those language design choices. On some level they are justified. They make it so you need to go pretty far out of your way to try and call the method, and if you really need it that badly, you must have a pretty good reason!

Debugging hooks and testing come to mind as possible applications, used responsibly of course.


回答 9

在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'

https://docs.python.org/3/tutorial/classes.html#tut-private

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

即使问题很旧,我也希望我的摘录对您有所帮助。

With Python 3.4 this is the behaviour:

>>> 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'

https://docs.python.org/3/tutorial/classes.html#tut-private

Note that the mangling rules are designed mostly to avoid accidents; it still is possible to access or modify a variable that is considered private. This can even be useful in special circumstances, such as in the debugger.

Even if the question is old I hope my snippet could be helpful.


回答 10

关于私有方法和属性的最重要的考虑是告诉开发人员不要在类之外调用它,这就是封装。人们可能会误解封装的安全性。当一个人故意使用您提到的那种语法时,您就不需要封装。

obj._MyClass__myPrivateMethod()

我已经从C#迁移了,起初对我来说也很奇怪,但是过了一会儿我才想到,只有Python代码设计人员对OOP的思考方式有所不同。

The most important concern about private methods and attributes is to tell developers not to call it outside the class and this is encapsulation. one may misunderstand security from encapsulation. when one deliberately uses syntax like that(bellow) you mentioned, you do not want encapsulation.

obj._MyClass__myPrivateMethod()

I have migrated from C# and at first it was weird for me too but after a while I came to the idea that only the way that Python code designers think about OOP is different.


回答 11

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

据我了解,它们不能是私有的。如何保护隐私?

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

Why are Python’s ‘private’ methods not actually private?

As I understand it, they can’t be private. How could privacy be enforced?

The obvious answer is “private members can only be accessed through self“, but that wouldn’t work – self is not special in Python, it is nothing more than a commonly-used name for the first parameter of a function.