Search code examples
pythonoopstackprivatepublic

Public and private methods in Python


I am trying to change a public to private parameter inside a Python class. As far as I know, to make it private I need to declare for instance:

self.__top = None # <-- Instead of self.top = None

However, I cannot figure out how to make a private struct with private properties, such that they are called properly in the public methods.

For instance:

class Stack:

    def __init__(self, size=None):
        self.__top = None
        if size is None:  # if size is unset
            self.__size = -1
        else:
            self.__size = size
        self.__current_size = -1

    def push(self, data):
        if self.current_size >= self.size: # ERROR!
            print("Stack Overflow!")
            return

Solution

  • I'm assuming that by using terms such as struct, public and private you must come from a background of C/C++. There are no such things in Python, and the naming of the attributes are purely conventional.

    I recommend reading What is the meaning of a single and a double underscore before an object name?.

    Typically for your "private" attributes which you don't want for others to use outside of your class, the convention is to prefix it with a single underscore _, like _size. If you plan on using this outside, it boils down to these cases:

    • do you want it to be writable from outside? In that case you just define it as size and use it like this everywhere
    • do you want it to be read-only from outside? In this case you can make it private and make a property for it like:

    Code:

    class A:
    
        self __init__(self, size):
            self._size = size
    
        @property
        def size(self):
            return self._size
    

    You also have the ability to translate the internal variable to another name, and make it writable at the same time under that different name.

    Example:

    class A:
    
        def __init__(self, value):
            self._internal_var = value
    
        def set_data(self, value):
            self._internal_var = value
    
        def get_data(self):
            return self._internal_var
    
        data = property(get_data, set_data)
    

    Or alternatively:

    @property
    def data(self):
        return self._internal_var
    
    @data.setter
    def data(self, value):
        self._internal_var = value
    

    Then if you call

    a1 = A(11)
    print(a1.data)
    a1.data = 22
    print(a1.data)
    

    it will yield:

    11
    22