Underline, double underline in Python

Single and double underscores have their own meanings in Python variable names and method names. Some are only used as conventions to prompt developers; Others have special meaning for Python interpreters.

In general, there are several situations:

  • Front single underline:_ var
  • Post single underline: var_
  • Leading double underline:__ var
  • Double underline before and after:__ var__
  • Single underline:_

1. Front single underline:_ var

When variable names and method names are involved, the preceding single underscore has only the agreed meaning. It is a reminder to programmers that the Python community has agreed that a single underline means something, and it itself will not affect the behavior of the program. The pre underscore means to remind other programmers that variables or methods starting with a single underscore are only used internally. It is only a hint, without any binding force.

For example:

If you instantiate this class and try to access__ init__ am and defined in constructor_ aomi attribute, what happens?

class ceshi:
   def __init__(self):
      self.am = 2021
      self._aomi = 2022
t = ceshi()
print(t._aomi)

 

As you can see_ The single underscore in front of aomi does not prevent us from "entering" the class to access the value of the variable.

This is because the leading single underscore in Python is only a recognized convention, at least when it comes to variable and method names. However, the leading underscore affects the way names are imported from the module.

For example, in my_module defines two methods, org_fun and_ new_fun

#my_module.py

def org_fun():
    return 2021

def _new_fun():
    return 2022

Test import:

If you use wildcard import to import all names from this module, Python does not import names with a single underscore before them

By the way, wildcard imports should be avoided because it is not clear which names exist in the current namespace. 10 for clarity, it is best to adhere to the conventional import method. Unlike wildcard import, regular import is not affected by the pre single underscore naming convention.

 

2. Post single underline: var_

Sometimes, the most appropriate name for a variable has been occupied by keywords in the python language. Therefore, names such as class or def cannot be used as variable names in Python. In this case, you can append an underscore to bypass the naming conflict.

In short, it is a convention to use a single underscore to avoid naming conflicts with Python keywords.

3. Double underline in front:__ var

The double underscore prefix causes the Python interpreter to override attribute names to avoid naming conflicts in subclasses.

This is also called name mangling, which means that the interpreter changes the name of the variable to avoid naming conflicts when extending the class later.

It sounds very abstract. Let's experiment with a code example:

class Test:
   def __init__(self):
       self.foo = 11
       self._bar = 23
       self.__baz = 23

Let's use the built-in dir() function to see the properties of this object:

>>> t = Test()
>>> dir(t)
['_Test__baz', '__class__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__weakref__', '_bar', 'foo']

The above is a list of the properties of this object. Let's look at this list and look for our original variable name foo_ bar and__ baz - I'm sure you'll notice some interesting changes.

self. The foo variable is displayed in the attribute list as unmodified as foo.

self._bar behaves the same way - it acts in_ bar is displayed on the class. As I said before, in this case, the leading underline is just a convention. Just give the programmer a hint. However, for self__ For baz, the situation looks a little different. When you search in this list__ baz, you won't see a variable with this name.

__ What happened to baz?

If you look closely, you will see that there is a name on this object_ Test__ Properties of Baz. This is the name modification made by the Python interpreter. It does this to prevent variables from being overridden in subclasses.

Let's create another class that extends the Test class and try to override the existing properties added in the constructor:

class ExtendedTest(Test):
   def __init__(self):
       super().__init__()
       self.foo = 'overridden'
       self._bar = 'overridden'
       self.__baz = 'overridden'

Now, you think foo_ bar and__ Will the value of baz appear on the instance of this ExtendedTest class? Let's take a look:

>>> t2 = ExtendedTest()
>>> t2.foo
'overridden'
>>> t2._bar
'overridden'
>>> t2.__baz
AttributeError: "'ExtendedTest' object has no attribute '__baz'"

Wait a minute, when we try to see T2__ Why do we get AttributeError when the value of baz? Name modification is triggered again! It turns out that this object doesn't even have__ baz attribute:

>>> dir(t2)
['_ExtendedTest__baz', '_Test__baz', '__class__', '__delattr__',
'__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__', '__init__', '__le__',
'__lt__', '__module__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '__weakref__', '_bar', 'foo', 'get_vars']

As you can see__ baz becomes_ ExtendedTest__baz to prevent accidental modifications:

>>> t2._ExtendedTest__baz
'overridden'

But the original_ Test__baz is still:

>>> t2._Test__baz
42

Double underlined name decoration is completely transparent to programmers. This is confirmed by the following examples:

class ManglingTest:
   def __init__(self):
       self.__mangled = 'hello'

   def get_mangled(self):
       return self.__mangled

>>> ManglingTest().get_mangled()
'hello'
>>> ManglingTest().__mangled
AttributeError: "'ManglingTest' object has no attribute '__mangled'"

Does the name modifier also apply to method names? Yes, it also applies. Name decoration affects all names that begin with two underscore characters ("dunders") in the context of a class:

class MangledMethod:
   def __method(self):
       return 42

   def call_it(self):
       return self.__method()

>>> MangledMethod().__method()
AttributeError: "'MangledMethod' object has no attribute '__method'"
>>> MangledMethod().call_it()
42

This is another perhaps surprising example of the use of name modification:

_MangledGlobal__mangled = 23

class MangledGlobal:
   def test(self):
       return __mangled

>>> MangledGlobal().test()
23

In this example, I declare a_ MangledGlobal__ Global variable of mangled. I then access the variables in the context of a class called mangledglobal. Because of the name modification, I can in the test() method of the class__ Mangled to reference_ MangledGlobal__mangled global variable.

The Python interpreter automatically converts the name__ mangled extended to_ MangledGlobal__mangled because it starts with two underscore characters. This indicates that name modifiers are not specifically associated with class properties. It applies to any name that begins with two underscore characters used in the context of the class.

There's a lot to absorb.

To be honest, these examples and explanations didn't jump out of my mind. I did some research and processing to get it out. I've been using Python for many years, but rules and special situations like this don't always come to mind.

Sometimes the most important skill for programmers is "pattern recognition" and know where to look up information. If you feel a little overwhelmed at this point, please don't worry. Take your time and try some examples in this article.

Immerse yourself in these concepts so that you can understand the general idea of name modification and some other behaviors I show you. If one day you meet them by chance, you will know what to look up in the document.

4. Double leading and double ending underline_ var_

Perhaps surprisingly, if a name starts and ends with a double underscore at the same time, the name modifier will not be applied. Variables surrounded by double underlined prefixes and suffixes are not modified by the Python interpreter:

class PrefixPostfixTest:
   def __init__(self):
       self.__bam__ = 42

>>> PrefixPostfixTest().__bam__
42

However, Python retains names with double leading and double trailing underscores for special purposes. Examples are__ init__ Object constructor, or__ call__ --- It enables an object to be called.

These dunder methods are often called magic methods - but many people in the Python community (including myself) don't like this method.

It is best to avoid using names that begin and end with double underscores ("dunders") in your own programs to avoid conflicts with future changes in the Python language.

5. Single underline_

By convention, sometimes a single independent underscore is used as a name to indicate that a variable is temporary or irrelevant.

For example, in the following loop, we do not need to access the running index, we can use "" To indicate that it is only a temporary value:

>>> for _ in range(32):
...    print('Hello, World.')

You can also use a single underscore as an "indifferent" variable in an unpacking expression to ignore specific values. Again, this meaning is "by convention" and does not trigger special behavior in the Python interpreter. A single underscore is just a valid variable name, which can be used for this purpose.

In the following code example, I split the car tuple into separate variables, but I'm only interested in color and mileage values. However, for the split expression to run successfully, I need to assign all the values contained in the tuple to the variable. In this case, "" It can be used as a placeholder variable:

>>> car = ('red', 'auto', 12, 3812.4)
>>> color, _, _, mileage = car

>>> color
'red'
>>> mileage
3812.4
>>> _
12

In addition to being used as a temporary variable, "" Is a special variable in most Python REPL that represents the result of the most recent expression evaluated by the interpreter.

This is very convenient. For example, you can access the results of previous calculations in an interpreter session, or you are dynamically building and interacting with multiple objects without assigning names to these objects in advance:

>>> 20 + 3
23
>>> _
23
>>> print(_)
23

>>> list()
[]
>>> _.append(1)
>>> _.append(2)
>>> _.append(3)
>>> _
[1, 2, 3]

Python underline naming mode - Summary

The following is a short summary, the "quick look-up table", which lists the meanings of the five Python underline modes I talked about in this article:

 

Keywords: Python Back-end

Added by cupboy on Tue, 04 Jan 2022 15:33:08 +0200