Python Advanced Learning Notes (ii)

Source: Internet
Author: User
Tags ming uppercase letter

(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)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.