Explanation of the _ init _ () method and Python _ init _ in python __
The _ init _ () method has two major reasons. The first reason is that initialization is the most important step in the object lifecycle; each object must be correctly initialized before it can work normally. The second reason is that the _ init _ () parameter value can be in multiple forms.
There are many ways to provide parameter values for _ init _ (). For a large number of Use Cases for object creation, we can look at several of them. We want to clarify as much as possible, so we need to define an initialization to correctly describe the problem area.
Before we use the _ init _ () method, we need to roughly and simply look at the hierarchy of the implicit object classes in Python.
In this chapter, let's take a look at the initialization of Simple objects in different forms (for example, playing cards ). After that, we can also look at more complex objects, like hands objects that contain collections and players that contain policies and States.
Implicit superclass -- object
Every Python class implies a superclass: object. It is a very simple class definition and does almost nothing. We can create an object instance, but we cannot use it to do too much, because many special methods are easy to throw exceptions.
When we customize a class, the object is a superclass. The following is a class definition example, which uses the new name to simply inherit the object:
class X: pass
Below are some interactions with custom classes:
>>> X.__class__<class 'type'>>>> X.__class__.__base__<class 'object'>
We can see that this class is an object of the type class, and its base class is object.
As we can see in each method, we also look at the default behavior inherited from the object. In some cases, the behavior of super-class special methods is what we want. In other cases, we need to override this special method.
Init () method of the base class Object
Object lifecycle is based on creation, initialization, and destruction. We have postponed the advanced special methods for creation and destruction to subsequent chapters. Currently, we only focus on initialization.
For all the super-class objects of the class, there is a _ init _ () implementation that includes pass by default. We do not need to implement _ init __(). If it is not implemented, instance variables will not be created after the object is created. In some cases, this default behavior is acceptable.
We always add attributes to an object. This object is a subclass of the base class object. Think about the following classes. Two instance variables are required but they are not initialized:
class Rectangle: def area(self): return self.length * self.width
The Rectangle class has a method that uses two attributes to return a value. These attributes are not initialized. This is a legitimate Python code. It can effectively avoid setting special properties. Although it is a bit strange, it is effective.
The interaction of the Rectangle class is as follows:
>>> r = Rectangle()>>> r.length, r.width = 13, 8>>> r.area()104
Obviously this is legal, but it is also the root cause of obfuscation, so it is also the reason we need to avoid.
In any case, this design gives great flexibility, so sometimes we do not need to set all attributes in the _ init _ () method. So far we have gone smoothly. An optional attribute is actually a subclass, but it is not officially declared as a subclass. To some extent, the creation of polymorphism may cause confusion and the improper use of if Statements. Uninitialized attributes may be useful, but may be a precursor to poor design.
Suggestions in "Zen of Python:
"Explicit is better than implicit. "
An _ init _ () method should explicitly display instance variables.
Poor Polymorphism
Flexibility and stupidity lie in the same mind.
When we think we need to write something like below, we are moving from the flexible edge to the stupid:
if 'x' in self.__dict__:
Or:
try: self.xexcept AttributeError:
It is time to reconsider the API and add a common method or attribute. Refactoring is more wise than adding an if statement.
Implement init () in the superclass ()
We initialize the object by implementing the _ init _ () method. When an object is created, Python first creates an empty object and then calls the _ init _ () method for the new object. This function is usually used to create instance variables of an object and perform any other one-time processing.
The following is the hierarchy defined by the Card class example. We will define the Card superclass and three subclasses, which are the variants of Card. The two instance variables are directly set by the parameter value, and the two variables are calculated through the initialization method:
class Card: def __init__(self, rank, suit): self.suit = suit self.rank = rank self.hard, self.soft = self._points()class NumberCard(Card): def _points(self): return int(self.rank), int(self.rank)class AceCard(Card): def _points(self): return 1, 11class FaceCard(Card): def _points(self): return 10, 10
In this example, we extract the _ init _ () method to the superclass, so that the general initialization in the Card superclass can be applied to the NumberCard, AceCard, and FaceCard sub-classes.
This is a common polymorphism design. Each subclass provides a unique _ points () method. All subclasses have the same signature: they have the same methods and attributes. The objects of these three sub-classes can be used in an application.
If you use simple characters for the color, you can create a Card instance as follows:
cards = [AceCard('A', '?'), NumberCard('2','?'), NumberCard('3','?'),]
In the list, we will list some card categories, card values, and colors. In the long run, we need more intelligent factory functions to create Card instances. Using this method to enumerate 52 cards is boring and error-prone. Before getting started with factory functions, let's look at some other issues.
Use init () to create an explicit constant
You can define a color category for the card. In, the color does not matter. A simple string can be used.
We use the color constructor as an example to create a constant object. In many cases, some objects in our application can be defined by a constant set. A small portion of static objects may be part of the implementation of policy mode or state mode.
In some cases, we have a constant Object pool created in the initialization or configuration file, or we can create a constant object based on command line parameters. We will obtain detailed information about the initialization design and startup design in Chapter 1 "copy through commands.
Python does not have a simple formal mechanism to define an immutable object. In chapter 3 "attribute access, method attributes, and Descriptors", we will look at the technology to ensure immutability. In this example, the color is immutable.
The following class is used to create four explicit constants:
class Suit: def __init__(self, name, symbol): self.name= name self.symbol= symbol
The constants created through this class are as follows:
Club, Diamond, Heart, Spade = Suit('Club','?'), Suit('Diamond','?'), Suit('Heart','?'), Suit('Spade','?')
Now we can use the code snippet shown below to create cards:
cards = [AceCard('A', Spade), NumberCard('2', Spade), NumberCard('3', Spade),]
In this small example, this method is not a huge improvement for the color code of a single feature. In more complex cases, some policies or status objects are created in this way. By reusing small, static constant objects, you can make the strategy or state design pattern more efficient.
We must admit that in Python these objects are not technically static and they are variable. It may be helpful to make these objects remain unchanged after extra encoding.
Immutability
Immutability is attractive, but it is easy to cause problems. Sometimes the mythical "malicious programmers" modify the constant value in their applications. It is very stupid in terms of design. These mythical and malicious programmers will not stop doing this, because there is no better way to code in Python in a simpler and simpler way. Malicious programmers access the source code and modify the code as easily as possible to modify a constant.
It is best not to struggle for too long when defining classes of immutable objects. In Chapter 3 attribute access, method attributes, and descriptors, we will demonstrate how to achieve immutability by providing appropriate diagnostic information in a bug program.