The difference between single and double underscores in Python

When learning Python, many people don't understand why a few underscores are added in front of a method, sometimes even on both sides, such as __this__this. Before I saw the above article, I always thought the role of Python in these underlined like in the case of Golang method / function like, or some other language private, publicthe same role, but carefully get to the bottom, it is not all Python The original intention of this design. Let's analyze in detail below.

Start with a single underscore

We often see a single underscore in front of a method or attribute, and think it means that the method or attribute is a private method of the type (Python and Golang, not only classes can have methods, many types and even basic types can also define methods) private methods or Attributes. But in fact, there is no real private method or attribute in Python. The single underscore _just means that you should not access this method or attribute because it is not part of the API. for example:

Python

class BaseForm(StrAndUnicode):
    ...

    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

This code snippet comes from the Django source code (django/forms/forms.py). The design of this code is that the errorsproperties are part of the external API. If you want to get the error details, you should access the errorsproperties, not (and should not) access the _get_errorsmethods.

Start with double underscore

Many people told me before that the double underscore in Python means private. I have seen this statement in many places. This understanding may not be wrong, but this is not the original intention and purpose of Python designing the double underscore at the beginning. The real purpose of Python designing this is only to prevent the subclass from overriding the method of the parent class. Let's look at an example:

Python

class A(object):
    
    def __method(self):
        print("I'm a method in class A")

    def method_x(self):
        print("I'm another method in class A\n")

    def method(self):
        self.__method()
        self.method_x()

class B(A):
    
    def __method(self):
        print("I'm a method in class B")

    def method_x(self):
        print("I'm another method in class B\n")


if __name__ == '__main__':
    
    print("situation 1:")
    a = A()
    a.method()

    b = B()
    b.method()

    print("situation 2:")
    # a.__method()
    a._A__method() 

Results of the:

situation 1:
I'm a method in class A
I'm another method in class A

I'm a method in class A
I'm another method in class B

situation 2:
I'm a method in class A

There are two points to note here:

  1. In class A, we define three methods __method(), method_xand method(); then we redefine a class B, inherited from A, and override the __method()and method_xmethods of its parent class in class B, but from the output result, the B object When calling the method()method, the method of its parent class A __method()and its own method are called method_x(). In other words, the __method()overwrite did not take effect, but the method_x()overwrite took effect. And this is the sole purpose of Python designing the beginning of a double underscore. This point can also be answered in the official Python description:  www.python.org/dev/peps/pe ...
  2. As we said earlier, there are no real private variables in Python. Although we cannot directly quote the methods and attributes beginning with a double underscore, it is because Python adds a prefix in front of it by default _类名, so like the situation 2following code, although we cannot use adirect access __method(), we can add a prefix to access, that is _A__method().

Double underscore at the beginning and end

Generally speaking, __this__this method with double underscores at the beginning and end means that this is called by Python itself, and you should not call it. For example, we can call a len()function to find the length, but it actually calls the __len__()method in the background . Generally, we should use leninstead of directly __len__():

Python

a = [1, 2, 3]
print(len(a))   
print(a.__len__()) # 和上面等效

num = 10
print(num + 10)
print(num.__add__(10))  # 和上面等效

We generally call __len__()this method magic methods, and some operators call these magic methods in the +background . For example, the background call is __add__, the -call is __sub__, so this mechanism allows us to override the operator in our class (see Example later). In addition, sometimes this double-underline method at the beginning and end is just a callback function for certain special scenarios, such as __init__()when the object is initialized, when __new__()an instance is built, and so on. Let's look at two examples:

Python

class CrazyNumber(object):
    def __init__(self, n): 
        self.n = n 
    def __add__(self, other): 
        return self.n - other 
    def __sub__(self, other): 
        return self.n + other 
    def __str__(self): 
        return str(self.n) 

num = CrazyNumber(10) 
print(num) # output is: 10
print(num + 5) # output is: 5
print(num - 20) # output is: 30

In the above example, we have overwritten the +and -operators, swapping their functions. Look at another example:

Python

class Room(object):
    def __init__(self): 
        self.people = [] 
    def add(self, person): 
        self.people.append(person) 
    def __len__(self): 
        return len(self.people)
 
room = Room() 
room.add("Igor") 
print len(room) # output is: 1

In this example, because we have implemented it __len__(), the Roomobject can also use lenfunctions.

All such methods are explained here: documentation .

in conclusion

  1. Use a single underscore (_one_underline) at the beginning to indicate that the method is not part of the API and should not be accessed directly (although there is no problem with syntax access).
  2. Start with a double underscore (__two_underlines) to indicate that subclasses cannot override this method. Don't use this method unless you really know what you are doing.
  3. When you want the object itself may be defined as built-in objects, like Python Python built using some function or operator (such as len, add, +, -, ==etc.), you can define such methods.
  4. Of course, some attributes are only added at the end but underscore. This is just to avoid conflicts between some of our names and Python reserved keywords, and has no special meaning.

Guess you like

Origin blog.csdn.net/ytp552200ytp/article/details/108217017