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:
xx
Public variables/methods_xx
Leading single underscore__xx
Leading double underscore__xx__
Double underline before and afterxx_
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
_ name
The variable, function, or class is in usefrom xxx import *
Will not be imported.__ name
The instance properties and methods of theName Mangling >>> _ Class name __ Attribute name
支那- The name of the property in the parent class
__ name
Subclasses do not inherit, and subclasses cannot access. - If in subclass to
__ name
Assign 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.