33

I would like to have a function in my class, which I am going to use only inside methods of this class. I will not call it outside the implementations of these methods. In C++, I would use a method declared in the private section of the class. What is the best way to implement such a function in Python?

I am thinking of using a static decorator for this case. Can I use a function without any decorators and the self word?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
freude
  • 3,632
  • 3
  • 32
  • 51
  • 5
    There's no real "private" methods in Python. See [this question](http://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private) - more specifically, [this answer](http://stackoverflow.com/a/70555/264775). – thegrinner Jun 19 '13 at 14:11
  • I am asking about good style to do that – freude Jun 19 '13 at 14:12
  • 1
    staticmethods and "private" methods are two different things ... Can you explain what you actually want? do you want a method that is both static and private? – mgilson Jun 19 '13 at 14:12
  • 3
    Good style is to prepend the method name with an underscore. – Matthias Jun 19 '13 at 14:13

5 Answers5

53

Python doesn't have the concept of private methods or attributes. It's all about how you implement your class. But you can use pseudo-private variables (name mangling); any variable preceded by __(two underscores) becomes a pseudo-private variable.

From the documentation:

Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

class A:
    def __private(self):
       pass

So __private now actually becomes _A__private.

Example of a static method:

>>> class A:
...     @staticmethod         # Not required in Python 3.x
...     def __private():
...         print 'hello'
...
>>> A._A__private()
hello
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • Can I do just def __private(): pass without self? And then call it __private() in my class. Can I access this function outside the class? – freude Jun 19 '13 at 14:15
  • @freude you've define it as a static method then and call it as : `A._A__private()` – Ashwini Chaudhary Jun 19 '13 at 14:16
  • What does it mean static in this case? – freude Jun 19 '13 at 14:16
  • 4
    The goal of `__` is to avoid clashes with subclasses. It does this by name mangling, incorporating the class name in the variable. The fact that that makes the variable harder to find and access is a side-effect. – Martijn Pieters Jun 19 '13 at 14:17
  • @freude static means you can use it as a normal function, no need of passing the instance. – Ashwini Chaudhary Jun 19 '13 at 14:18
  • I think I does not need a decorator in my case. I am not going to relate it to any instance. It is like a service function working inside the class to make code more compact and modal, since I use it in many other methods of the class – freude Jun 19 '13 at 14:24
  • 2
    You do need a decorator. Python treats the first argument of class methods specially, so unless you apply `@staticmethod` or a similar decorator, you'll get an error. – alexis Jun 19 '13 at 14:24
  • Python 3 docs update: https://docs.python.org/3/tutorial/classes.html#tut-private – dijonkitchen May 18 '23 at 20:31
9

Python doesn't have the concept of 'private' the way many other languages do. It is built on the consenting adult principle that says that users of your code will use it responsibly. By convention, attributes starting with a single or double leading underscore will be treated as part of the internal implementation, but they are not actually hidden from users. Double underscore will cause name mangling of the attribute name though.

Also, note that self is only special by convention, not by any feature of the language. Instance methods, when called as members of an instance, are implicitly passed the instance as a first argument, but in the implementation of the method itself, that argument can technically be named any arbitrary thing you want. self is just the convention for ease of understanding code. As a result, not including self in the signature of a method has no actual functional effect other than causing the implicit instance argument to be assigned to the next variable name in the signature.

This is of course different for class methods, which receive the instance of the class object itself as an implicit first argument, and static methods, which receive no implicit arguments at all.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Silas Ray
  • 25,682
  • 5
  • 48
  • 63
6

There is plenty of great stuff here with obfuscation using leading underscores. Personally, I benefit greatly from the language design decision to make everything public as it reduces the time it takes to understand and use new modules.

However, if you're determined to implement private attributes/methods and you're willing to be unpythonic, you could do something along the lines of:

from pprint import pprint


# CamelCase because it 'acts' like a class
def SneakyCounter():

    class SneakyCounterInternal(object):

        def __init__(self):
            self.counter = 0

        def add_two(self):
            self.increment()
            self.increment()

        def increment(self):
            self.counter += 1

        def reset(self):
            print 'count prior to reset: {}'.format(self.counter)
            self.counter = 0

    sneaky_counter = SneakyCounterInternal()

    class SneakyCounterExternal(object):

        def add_two(self):
            sneaky_counter.add_two()

        def reset(self):
            sneaky_counter.reset()

    return SneakyCounterExternal()


# counter attribute is not accessible from out here
sneaky_counter = SneakyCounter()

sneaky_counter.add_two()
sneaky_counter.add_two()
sneaky_counter.reset()

# `increment` and `counter` not exposed (AFAIK)
pprint(dir(sneaky_counter))

It is hard to imagine a case where you'd want to do this, but it is possible.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
circld
  • 632
  • 1
  • 7
  • 14
5

Python just doesn't do private. If you like you can follow convention and precede the name with a single underscore, but it's up to other coders to respect that in a gentlemanly† fashion

† or gentlewomanly

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
2

You just don't do it:

  • The Pythonic way is to not document those methods/members using docstrings, only with "real" code comments. And the convention is to append a single or a double underscore to them;

  • Then you can use double underscores in front of your member, so they are made local to the class (it's mostly name mangling, i.e., the real name of the member outside of the class becomes: instance.__classname_membername). It's useful to avoid conflicts when using inheritance, or create a "private space" between children of a class.

  • As far as I can tell, it is possible to "hide" variables using metaclasses, but that violates the whole philosophy of Python, so I won't go into details about that.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zmo
  • 24,463
  • 4
  • 54
  • 90
  • 3
    double underscore activates name mangling. This is definitely not the same as private – John La Rooy Jun 19 '13 at 14:14
  • that's exactly what I say: you don't do it, but you use conventions! – zmo Jun 19 '13 at 14:15
  • 1
    You can obfuscate attribute access via metaclasses, and you can make read-only attributes and implement the private/setter/getter pattern with decorators or metaclasses, but the only way to obfuscate something to the point that someone truely cannot get at it from within Python code is to hide it in a C-extension. – Silas Ray Jun 19 '13 at 14:17