(related to content: Object-oriented, class-based inheritance) defining classes and creating instances
In Python, classes are defined by the class keyword. For example, define a person class as follows:
class Person (object): Pass
According to Python 's programming habits, the class name begins with an uppercase letter, followed by (object), indicating which class the class inherits from. The inheritance of classes is explained in a later section, and now we simply inherit from the object class.
With the definition of the person class, you can create concrete instances such as xiaoming, Xiaohong , and so on. Creating an instance is created using the class name + (), like a function call:
Xiaoming = person () Xiaohong = person ()
Create Instance Properties
Although you can create instances of xiaoming, Xiaohong , and so on through the person class, these instances are not as different as they seem to be in different addresses. In the real world, distinguish xiaoming, Xiaohong to rely on their respective names, gender, birthdays and other attributes.
How do I get each instance to have its own different properties? Since Python is a dynamic language, for each instance, you can assign values directly to their properties, for example, by adding the name, gender , and birth attributes to the instance of xiaoming :
Xiaoming = person () Xiaoming.name = ' Xiao Ming ' xiaoming.gender = ' Male ' Xiaoming.birth = ' 1990-1-1 '
The attributes added to Xiaohong are not necessarily the same as xiaoming :
Xiaohong = person () Xiaohong.name = ' Xiao Hong ' Xiaohong.school = ' No. 1 high school ' Xiaohong.grade = 2
The properties of an instance can be manipulated like normal variables:
Xiaohong.grade = Xiaohong.grade + 1
Initializing instance Properties
While we are free to bind various properties to an instance, in the real world, an instance of a type should have properties of the same name. For example, what if the personclass should have the name, gender , and birth properties when it is created?
When defining the person class, you can add a special __init__ () method to the person class, and when the instance is created, the__init__ () method is automatically called, and we can then unify the following properties for each instance:
class Person (object): def __init__ (self, name, gender, birth): self.name = name Self.gender = Gender Self.birth = Birth
The first argument of the __init__ () method must be self (or another name, but it is recommended to use idioms), and subsequent arguments can be freely specified, and there is no difference between defining a function.
Accordingly, when you create an instance, you must provide parameters other than self:
Xiaoming = Person (' Xiao Ming ', ' Male ', ' 1991-1-1 ') Xiaohong = person (' Xiao Hong ', ' Female ', ' 1992-2-2 ')
With the __init__ () method, each person instance is created with 3 attributes of name, gender , and birth , and is given a different property value, and the Access property uses the. Operator:
Print xiaoming.name# output ' Xiao Ming ' print xiaohong.birth# output ' 1992-2-2 '
It is important to note that the beginner definition __init__ () method often forgets the self parameter:
>>> class Person (object): ... def __init__ (name, gender, birth): ... Pass ... >>> xiaoming = person (' Xiao Ming ', ' Male ', ' 1990-1-1 ') Traceback (most recent call last): File "<st Din> ", line 1, in <module>typeerror: __init__ () takes exactly 3 arguments (4 given)
This can cause the creation to fail or run abnormally because the first parameter, name, is passed to the instance's reference by the Python interpreter, causing the entire method's call parameter position to be completely out of alignment.
Please define
PersonThe __init__ method of the class, in addition to accepting
name, genderAnd
Birth, you can also accept any keyword arguments and assign them all as attributes to the instance.
To define keyword parameters, use **kw;
In addition to setting a property directly using self.name = ' xxx ' , you can also set properties by setattr (self, ' name ', ' xxx ') .
Reference code:
class Person (object): def __init__ (self, name, gender, birth, **kw): self.name = name Self.gender = gender< C3/>self.birth = Birth for K, V in Kw.iteritems (): setattr (self, k, v) xiaoming = person (' Xiao Ming ', ' Male ', ' 1990 -1-1 ', job= ' Student ') print Xiaoming.nameprint xiaoming.job
Access restrictions
We can bind a lot of properties to an instance, what if some attributes do not want to be accessed externally?
Python's control over property permissions is implemented by property names, which cannot be accessed externally if an attribute starts with a double underscore (__). See Example:
class Person (object): def __init__ (self, name): self.name = name self._title = ' Mr ' self.__job = ' Student ' P = person (' Bob ') print p.name# = Bobprint p._title# = Mrprint p.__job# = Errortraceback (most recent C All last): File "<stdin>", line 1, in <module>attributeerror: ' Person ' object have no attribute ' __job '
As can be seen, only "__job" that begins with a double underscore cannot be accessed directly externally.
However, if a property is defined as "__xxx__", then it can be accessed externally, the attribute defined in "__xxx__" is called a special attribute in the Python class, there are many predefined special attributes that can be used, and usually we do not use the common attribute "__xxx__ "Definition.
The attribute "_xxx", which begins with a single underscore, can also be accessed externally, but, by habit, they should not be accessed externally.
Creating Class Properties
A class is a template, whereas an instance is an object created from a class.
A property that is bound on one instance does not affect other instances, but the class itself is an object, and if you bind a property to a class, all instances can access the properties of the class, and the class properties accessed by all instances are the same! That is, instance properties each have each instance owned and independent of each other, and the class attribute has only one copy.
Defining class properties can be defined directly in class:
class Person (object): address = ' Earth ' def __init__ (self, name): self.name = name
Because class properties are directly bound to classes, access to class properties does not require an instance to be created and can be accessed directly:
Print person.address# = Earth
A property that invokes a class on an instance is also accessible, and all instances have access to the properties of the class to which it belongs:
P1 = person (' Bob ') P2 = person (' Alice ') print p1.address# = Earthprint p2.address# = Earth
Because Python is a dynamic language, class properties can be added and modified dynamically:
person.address = ' China ' Print p1.address# + ' China ' print p2.address# + ' China '
Because the class attribute has only one copy, when the address of the person class changes, the class properties accessed by all instances change.
What about class properties and instance property name collisions?
Modifying a class property causes all of the class properties accessed by the instance to be affected, but what happens if the Class property is modified on an instance variable?
class Person (object): address = ' Earth ' def __init__ (self, name): self.name = NAMEP1 = Person (' Bob ') P2 = Pers On (' Alice ') print ' person.address = ' + Person.addressp1.address = ' China ' print ' p1.address = ' + p1.addressprint ' Person.a ddress = ' + person.addressprint ' p2.address = ' + p2.address
The results are as follows:
person.address = earthp1.address = chinaperson.address = Earthp2.address = Earth
We found that after setting the p1.address = ' China ' , the P1 access address did become ' China ', but Person.Address and p2.address are still ' earch ', what's going on?
The reason for this is that p1.address = ' China ' does not change the address of theperson, but instead binds the instance attribute address to the P1 instance , and for P1 it has an instance attribute address (the value is ' China '), and the class person to which it belongs has a class attribute address, so:
Visit P1.address , first find the instance property and return ' China '.
Visit P2.address , p2 does not have an instance attribute address, but has a class attribute address, and therefore returns ' Earth '.
It can be seen that when instance properties and class attributes have the same name, the instance property has a high precedence, which masks access to the class properties.
When we delete the P1 address instance property, access to P1.address returns the value of the class attribute ' Earth ':
del p1.addressprint p1.address# = Earth
As you can see, never modify a class property on an instance, it does not actually modify the class property, but instead binds the instance to an instance property.
Defining instance methods
The private property of an instance is a property that begins with __ and cannot be accessed externally, what is the use of these attribute definitions?
Although private properties cannot be accessed externally, they can be accessed from within the class. In addition to defining the properties of an instance, you can define the methods of the instance.
An instance is a function defined in a class whose first argument is always self, pointing to the instance itself that invokes the method, and the other arguments are exactly the same as a normal function:
class Person (object): def __init__ (self, name): self.__name = name def get_name (self): return self.__ Name
get_name (self) is an instance method whose first argument is self. __init__ (self, name) can also be seen as a special instance method.
The invocation instance method must be called on the instance:
P1 = person (' Bob ') print p1.get_name () # Self does not need to be explicitly passed in # = Bob
Within an instance method, all instance properties can be accessed, so that if the external needs access to private properties, which can be obtained through a method call, the form of the data encapsulation can simplify the external invocation in addition to protecting internal data consistency.
Method is also a property
The instance method that we define in class is actually a property, which is actually a function object:
class Person (object): def __init__ (self, Name, score): self.name = name Self.score = Score def get_ Grade (self): return ' A ' p1 = person (' Bob ', "all") print p1.get_grade# = <bound method Person.get_grade of <__ma in__. Person object at 0x109e58510>>print p1.get_grade () # = A
In other words,p1.get_grade Returns a function object, but this function is a function bound to an instance, andP1.get_grade () is the method call.
Because the method is also a property, it can also be dynamically added to the instance, just need to use types. Methodtype () turns a function into a method:
Import Typesdef Fn_get_grade (self): if Self.score >=: return ' A ' if Self.score >=: return ' B ' return ' C ' class Person (object): def __init__ (self, Name, score): self.name = name Self.score = SCOREP1 = person (' Bob ', p1.get_grade) = types. Methodtype (Fn_get_grade, p1, person) print P1.get_grade () # + AP2 = person (' Alice ', $) Print p2.get_grade () # Error:att Ributeerror: ' Person ' object with no attribute ' Get_grade ' # because P2 instance is not bound Get_grade
Adding a method to an instance dynamically is not uncommon, and it is more intuitive to define it directly in class.
Defining class methods
Similar to attributes, methods are also divided into instance methods and class methods.
All defined in class are instance methods, and the first argument of the instance method is the instance itself.
To define a class method in class, you need to write this:
class Person (object): count = 0 @classmethod def how_many (CLS): return cls.count def __init__ ( Self, name): self.name = name Person.count = person.count + 1print person.how_many () p1 = person (' Bob ') print Perso N.how_many ()
By marking a @classmethod, the method binds to the person class, not to an instance of the class. The first parameter of the class method is passed into the class itself, usually named the parameter name CLS, and the above Cls.count is actually equivalent to person.count.
Because it is called on the class, not on the instance, the class method cannot get any instance variables, only the reference to the class is obtained.
Inherit a class
If you have defined the person class and need to define the new Student and Teacher classes, you can inherit directly from the person class:
class Person (object): def __init__ (self, Name, gender): self.name = name Self.gender = Gender
When defining the Student class, you only need to add additional attributes, such as score:
Class Student: def __init__ (self, name, gender, score): super (Student, self). __INIT__ (name, gender) Self.score = Score
Be sure to use super (Student, self). __INIT__ (name, gender) to initialize the parent class, otherwise, Student that inherits from person will not have name and >gender.
The function super (Student, self) returns the parent class that inherits from the current class, that is, person, and then calls the __init__ () method, noting that the from parameter has been passed in super (), in __ Init__ () is implicitly passed and does not need to be written out (nor written).
Judging type
The function isinstance () can determine the type of a variable that can be used in Python's built-in data types such as str, list, dict, or in our custom classes, which are essentially data types.
Assume that the definition and inheritance of the following person , Student , and Teacher are as follows:
class Person (object): def __init__ (self, Name, gender): self.name = name Self.gender = Genderclass Student ( Person): def __init__ (self, name, gender, score): super (Student, self). __INIT__ (name, gender) Self.score = Scoreclass Teacher: def __init__ (self, name, gender, course): super (Teacher, self). __INIT__ (Name, gender) Self.course = Coursep = Person (' Tim ', ' Male ') s = Student (' Bob ', ' Male ',) t = Teacher (' Alice ', ' Female ', ' Eng Lish ')
When we get the variable p, s, T , we can use isinstance to determine the type:
>>> isinstance (p, person) True # p is the person type >>> isinstance (P, Student) False # p is not a Student type >>> isinstance (P, Teacher) False # p is not a Teacher type
This means that on the inheritance chain, an instance of a parent class cannot be a subclass type, because the child analogy parent has more properties and methods.
We re-examine s:
>>> Isinstance (S, person) True # s is the person type >>> isinstance (S, Student) True # s is the Student type > >> Isinstance (S, Teacher) False # s is not a Teacher type
s is student type, not teacher type, which is easy to understand. However,s is also the person type because student inherits from person, although it has more properties and methods than person, but it is also possible to consider s as an instance of person.
This means that on an inheritance chain, an instance can be regarded as its own type, or as the type of its parent class.
Polymorphic
Class has an inheritance relationship, and the subclass type can be transformed upward as a parent class type, if we derive Student and Teacher from person, and both write a WhoAmI () method:
class Person (object): def __init__ (self, Name, gender): self.name = name Self.gender = Gender def WhoAmI (self): return ' I am a person, my name is%s '% Self.nameclass Student (person): def __init__ (self, name, Gen Der, score): super (Student, self). __INIT__ (name, gender) Self.score = score def whoAmI (self): return ' I am a Student, my name is%s '% Self.nameclass Teacher (person): def __init__ (self, name, gender, course): Supe R (Teacher, self). __INIT__ (name, gender) Self.course = Course def whoAmI (self): return ' I am a Teacher, my Name is%s '% Self.name
In a function, if we receive a variable x, the result can be printed correctly whether the x is a person , a Student , or a Teacher:
def who_am_i (x): print X.whoami () p = person (' Tim ', ' Male ') s = Student (' Bob ', ' Male ',) t = Teacher (' Alice ', ' Female ', ' 中文版 ') who_am_i (p) who_am_i (s) who_am_i (t)
Operation Result:
I am a person, my name is TimI am a Student, my name is Bobi am a Teacher, my name is Alice
This behavior is known as polymorphism. In other words, the method invocation will work on the actual type of x . s is the Student type, which actually has its own WhoAmI () method and the WhoAmI method inherited from person, but calls S.whoami () Always look for its own definition first, and if not, look up the inheritance chain until it is found in a parent class.
Because Python is a dynamic language, the parameter x passed to the function who_am_i (x) is not necessarily a subtype of person or person. An instance of any data type can, as long as it has a whoami () method:
Class Book (object): def WhoAmI (self): return ' I am a book '
This is one of the biggest differences between dynamic and static languages, such as Java. A dynamic language invokes an instance method, does not check the type, and can be called as long as the method exists and the parameter is correct.
Multiple inheritance
In addition to inheriting from a parent class, Python allows inheritance from multiple parent classes, called multiple inheritance.
The inheritance chain of multiple inheritance is not a tree, it looks like this:
Class A (object): def __init__ (Self, a): print ' init a ... ' self.a = AClass B (a): def __init__ (Self, a): C4/>super (B, self). __init__ (a) print ' init B ... ' class C (a): def __init__ (Self, a): super (C, self). __init_ _ (a) print ' init C ... ' Class D (B, C): def __init__ (Self, a): super (D, self). __init__ (a) print ' init D ...‘
See:
Like this,D also inherits from B and c, i.e. D has all the functions of A, B, and C . When multiple inheritance calls the __init__ () method through super () ,a is inherited two times, but __init__ () is called only once:
>>> d = d (' d ') init a...init c...init b...init D ...
The purpose of multiple inheritance is to select and inherit subclasses from the two inheritance trees, so that the composition function is used.
For example, Python's Web server has tcpserver, Udpserver, Unixstreamserver, Unixdatagramserver, and the server run mode has Multi-process Forkingmixin and multithreading threadingmixin two kinds.
To create a tcpserverfor a multi-process pattern:
Class Mytcpserver (TCPServer, forkingmixin) Pass
To create a udpserverfor multithreaded mode:
Class Myudpserver (Udpserver, threadingmixin): Pass
If there is no multiple inheritance, the 4x2=8 subclasses are required to implement all the possible combinations above.
Get object Information
To get a variable, in addition to using isinstance () to determine whether it is a certain type of instance, there is no other way to obtain more information?
For example, there are already definitions:
class Person (object): def __init__ (self, Name, gender): self.name = name Self.gender = Genderclass Student ( Person): def __init__ (self, name, gender, score): super (Student, self). __INIT__ (name, gender) Self.score = Score def whoAmI (self): return ' I am a Student, my name is%s '% Self.name
You can first get the type of the variable with the type () function , which returns a type object:
>>> type (123) <type ' int ' >>>> s = Student (' Bob ', ' Male ', A.) >>> type (s) <class ' __ main__. Student ' >
Second, you can use the dir () function to get all the properties of a variable:
>>> dir (123) # integers also have many properties ... [' __abs__ ', ' __add__ ', ' __and__ ', ' __class__ ', ' __cmp__ ', ...] >>> dir (s) [' __class__ ', ' __delattr__ ', ' __dict__ ', ' __doc__ ', ' __format__ ', ' __getattribute__ ', ' __hash__ ', ' __init__ ', ' __module__ ', ' __new__ ', ' __reduce__ ', ' __reduce_ex__ ', ' __repr__ ', ' __setattr__ ', ' __sizeof__ ', ' __str__ ', ' __subclasshook__ ', ' __weakref__ ', ' gender ', ' name ', ' score ', ' WhoAmI ']
For instance variables,dir () returns all instance properties, including those with a special meaning such as '__class__'. Notice that the method 'WhoAmI' is also an attribute of s .
How do you get rid of special properties such as ' __xxx__ ' , preserving only our own defined properties? Review the use of the filter () function.
The property returned by dir () is a list of strings, and if a property name is known, the getattr () and setattr () functions are required to get or set the properties of the object:
>>> GetAttr (S, ' name ') # Gets the Name property ' Bob ' >>> setattr (S, ' name ', ' Adam ') # Set the new Name property >> > s.name ' Adam ' >>> getattr (S, ' age ') # Gets the Age property, but the attribute does not exist, error: Traceback (most recent call last): File "& Lt;stdin> ", line 1, in <module>attributeerror: ' Student ' object have no attribute ' age ' >>> getattr (S, ' AG E ', #) # Gets the Age property and returns the default value 20:20 if the property does not exist
Python Advanced Learning Notes (ii)