简体   繁体   中英

Private methods in Python

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?

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 py3.x
...     def __private():
...         print 'hello'
...
>>> A._A__private()
hello

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.

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.

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

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, ie, 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM