The introduction

There are no real private properties or methods in Python, no real privatization, but there are naming conventions that let programmers deal with situations where privatization is needed, and we often need to distinguish between private methods and properties and public methods and properties for easy management and invocation. So how do you do that in Python?

There are several cases in naming variables and methods:

  • xxPublic variables/methods
  • _xxLeading single underscore
  • __xxLeading double underscore
  • __xx__Double underline before and after
  • xx_Single underline followed

The following sections describe each of these underlined naming features and differences.


_ Single leading underscore

A leading single underscore is meant to inform other programmers that variables or methods that begin with a single underscore are only used internally. This convention is defined in PEP 8, the most commonly used Python code style guide.

However, this convention has no special implications for the Python interpreter. Unlike Java, Python does not make a strong distinction between “private” and “public” variables. Adding an underscore before the variable name is more like someone hanging out a little underscore warning flag: “Note that this is not the public interface for this class. It’s best not to use it.”

The general Python convention is to make properties and methods preceded by a single underscore _ private, indicating that the properties and methods should not be called externally.

Of course, it is possible to name attributes or methods in a class with a single underscore. This simply means that the class’s definer expects the attributes or methods to be “private,” but it doesn’t really do anything. Such as:

# coding:utf8


class Sister() :

    def __init__(self, name, age, telphone) :
        self.name = name
        
        # Not recommended for external use
        self._age = age 
        self._telphone = telphone

    Allow external calls
    def show_age(self) :
        print("show_age() called")
        print("Little sister you really good-looking, kind of unique temperament, I do not know how old?")
        print(self._age)

        if self._age > 18:
            print("Little sister looks like an 18-year-old fairy.")
        else:
            print("Seriously, sister is so pretty.")
        print("Is it (✪ ✪ omega) \ n...")
        print("name: %s, phone: %s" % (self.name, self._telphone))
        print("end... \n")

        return self._age

    # It is not recommended to be called from outside
    def _get_age(self) :
        print("_get_age() called")
        print("Auntie how old are you?")
        print("18 would you believe it!!")
        print("end... \n")
        return self._age


def main() :

    s = Sister('Mary'.20.5201314)

    s.show_age()

    # callable but not recommended
    s._get_age()

    print(s.name)
    print(s._age)
    print(s._telphone)


if __name__ == '__main__':
    main()

         
Copy the code


Running results:

Little sister you really good-looking, have a unique temperament, I do not know how young?20Little sister looks like18Young fairies are Yang Yang... name: Mary, phone:5201314end... Auntie how old are you?18Believe it or not!!!!!! end... Mary20
5201314
[Finished in 0.1s]
Copy the code

As you can see, the previous single underscore _ does not prevent us from entering the class to access the value of the variable.

This is because leading single underscores are only an accepted convention in Python, at least when it comes to variable and method names.

However, leading underscores affect how names are imported from modules and are not imported by from somemodule import *.

# demo.py

_key = '123'

def _set_key(key) :
	global _key
	_key = key
Copy the code


# test.py
from demo import *

print(_key)
_set_key('567')
Copy the code

The interpreter throws an exception: NameError: name ‘_key’ is not defined.

Use wildcard imports to import all names from this module. Python does not import names with a leading single underscore (unless the __all__ list is defined in the module to override this behavior).

Py cannot be used in test.py because of the single underline variable/method in demo.py. Import module.

# test.py
import demo

print(demo._key)		# Normal use
demo._set_key('789')	# normal call
print(demo._key)		# Normal use
Copy the code


__ is preceded by a double underscore

For data encapsulation of an object, a property or method named this way is the private property or method of the class.

# coding:utf8


class Foo(object) :

	def __init__(self) :
		self__name = "private attribute"

	def getname() :
		return self.__name
		
	def __method() :
		print("private method")

	def run(self) :
		self.__method()
Copy the code


External access directly accesses private properties or methods

In [1] :# coding:utf8. :... :... :class Foo(object) :. :... :def __init__(self) :. : self.__name ="private attribute". :... :def getname(self) :. :returnself.__name ... :... :def __method(self) :. :print("private method")
   ...:
   ...:     def run(self) :
   ...:         self.__method()
   ...:
   ...:

In [2]: f = Foo()

In [3] : f.__name --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-3-332cfd3c796d> in <module>
----> 1 f.__name

AttributeError: 'Foo' object has no attribute '__name'

In [4] : f.__method() --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-4-9cb5f81c61a6> in <module>
----> 1 f.__method()

AttributeError: 'Foo' object has no attribute '__method'

In [5]: f.getname()
Out[5] :'private attribute'

In [6]: f.run()
private method
Copy the code

It can be found that it is not feasible, which serves to encapsulate hidden data. However, this implementation mechanism is not very strict. It is implemented by name reforming name Mangling in case the class accidentally overwrites the methods or attributes of the base class. But all names in a class that begin with a double underscore are automatically changed to the new name of _Class_object, such as __name >>> _Foo__name. We can also use dir() to see the details of class members

In [7] :dir(f)
Out[7] : ['_Foo__method'.'_Foo__name'.'__class__'.'__delattr__'.'__dict__'.'__dir__'.'__doc__'.'__eq__'.'__format__'.'__ge__'.'__getattribute__'.'__gt__'.'__hash__'.'__init__'.'__init_subclass__'.'__le__'.'__lt__'.'__module__'.'__ne__'.'__new__'.'__reduce__'.'__reduce_ex__'.'__repr__'.'__setattr__'.'__sizeof__'.'__str__'.'__subclasshook__'.'__weakref__'.'getname'.'run']

In [8]: f._Foo__name
Out[8] :'private attribute'

In [9]: f._Foo__method()
private method
Copy the code

This mechanism prevents an inherited class from redefining or changing the implementation of a method, for example, defining a word class Goo for Foo:

class Goo(Foo) :
	def __method(self) :
		print('private method of Goo')
Copy the code


Override the __method method to run:

In [11] :class Goo(Foo) :. :def __method(self) :. :print('private method of Goo')
    ...:

In [12]: g = Goo()

In [13]: g.run()
private method

In [14] :dir(g)
Out[14] : ['_Foo__method'.'_Foo__name'.'_Goo__method'. . ]Copy the code


When the run() method is called, the __method() method of class Foo is still executed, because self.__method() is automatically deformed to self._foo__method (), So does the Goo inherited run() method, and __method() method becomes _Goo__method().

Mangling’s technology is also called name decoration. In many modern programming languages, this technique is used to solve problems caused by the need for unique names, such as naming conflicts/overloading.


__ Double underscore __

The name, followed by a double underscore, is used for naming special methods that implement some behavior or function of an object. For example, __new__() is used to create instances, __init__() is used to initialize objects, and x + y operations are mapped to x.__add__(y). Sequences or dictionary index operation for x. x [k] mapping __getitem__ (k), __len__ (), the __str__ () respectively by built-in function len (), STR () call, and so on.

# coding:utf8


class Obj() :

    def __init__(self, num) :
        self.num = num
        self.li = list()
        self.li.append(num)

    def __add__(self, value) :
        print("__add__() execute")
        return self.num + value

    def __getitem__(self, index) :
        print("__getitem__() execute")
        return self.li[index]

    def __len__(self) :
        print("__len__() execute")
        return len(self.li)

    def __str__(self) :
        print("__str__() execute")
        return '<' + str(self.num) + '>'

    
def main() :
    a = Obj(5)
    a = a + 2
    print(a)

    b = Obj(6)
    print(b[0])
    print(len(b))
    print(b)


if __name__ == '__main__':
    main()

Copy the code


Test results:

__add__() execute
7
__getitem__() execute
6
__len__() execute
1
__str__() execute
< 6 >
[Finished in 0.1s]
Copy the code


Followed by single underscore _

Single underline behind to avoid collisions with Python keywords. As follows:

list_ = ["wang"."hui"."zack"]
dict_ = {
    "name": "hui"."age": 21
}
Copy the code


conclusion

  • _ nameThe variable, function, or class is in usefrom xxx import *Will not be imported.
  • __ nameThe instance properties and methods of theName Mangling >>> _ Class name __ Attribute name支那
  • The name of the property in the parent class__ nameSubclasses do not inherit, and subclasses cannot access.
  • If in subclass to__ nameAssign to an attribute defined in the subclass with the same name as the parent class.
  • __xx__Magic object or attribute that has a special function. Don’t name it like that.
  • xx_Used to avoid collisions with Python keywords.


The public,

Create a new folder X

Nature took tens of billions of years to create our real world, while programmers took hundreds of years to create a completely different virtual world. We knock out brick by brick with a keyboard and build everything with our brains. People see 1000 as authority. We defend 1024. We are not keyboard warriors, we are just extraordinary builders of ordinary world.