views:

7739

answers:

9

Python gives us the ability to create 'private' methods and variables within a class by prepending double underscores to the name, like so: *__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?

+34  A: 

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.

xsl
or as Guido van Rossum put it: "we are all adults."
hop
-1: this is just wrong. Double underscores is never meant to be used as private in first place. The answer from Alya below tells the real intention of name mangling syntax. The real convention is a single underscore.
nosklo
ok, kids, wait 'til you grow up to drink, smoke and access private variables.
mike
+5  A: 

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?

Maximilian
Not at all. I'm simply making the point that it's odd to give the developer an easy, and in my opinion way to magical, way of accessing 'private' properties.
wbowers
Yeah, I just tried to illustrate the point. Making it private just says "you shouldn't access this directly" by making the compiler complain. But one wants to really really do it he can. But yes, it's easier in Python than in most other languages.
Maximilian
+2  A: 

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.

Nickolay
A: 

Its 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.

ctcherry
+21  A: 

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.

Tony Meyer
so is there some sort of wrapper protocol that I'm supposed to use to access a protected variable?
intuited
There aren't "protected" variables any more than there are "private". If you want to access an attribute that starts with an underscore, you can just do it (but note that the author discourages this). If you must access an attribute that starts with a double underscore, you can do the name mangling yourself, but you almost certainly do not want to do this.
Tony Meyer
+33  A: 

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.

Alya
Very cool. I had no idea you could do that.
wbowers
Is this so? Where did you get that from?
miya
+2  A: 

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.

Ross
+2  A: 

When I first came form Java to Python i literately HATED this.

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

I love being on a platform, where people thrust each other, and I don't feel like anybody are forcing me away from anything in my code. In strongly encapsulated languages, if APIs have bugs, a workaround might just be a method call away, but if that method is private, then badluck. In Python they just say, sure, if you've read my code, and think it works, then good luck. :)

Thomas Ahle
+4  A: 

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 ###
arun
+1 This made me laugh :)
Thomas Ahle