1, Object oriented
as we said before, "a program is a collection of instructions", the statements we write in the program will become one or more instructions when executed, and then executed by the CPU. Of course, in order to simplify the program design, we introduce the concept of function, put relatively independent and frequently reused code into the function, and call the function when you need to use these functions; If the function of a function is too complex and bloated, we can further divide the function into sub functions to reduce the complexity of the system. But after saying so much, I don't know if you find that the so-called programming is that programmers control the computer to complete various tasks according to the working mode of the computer. However, the working mode of computer is different from the thinking mode of normal human beings. If programming must abandon the normal thinking mode of human beings to cater to the computer, the fun of programming will be much less. The heroic words of "everyone should learn programming" can only be said. Of course, these are not the most important. The most important thing is that when we need to develop a complex system, the complexity of the code will make development and maintenance difficult. Therefore, in the late 1960s, a series of concepts such as "software crisis" and "software engineering" began to appear in the industry.
the object-oriented programming idea introduced into Smalltalk programming language born in the 1970s (the prototype of object-oriented programming can be traced back to the earlier Simula language). According to this programming concept, the data in the program and the function of operating data are a logical whole, which we call "object", and our way to solve the problem is to create the required object and send various messages to the object. The cooperative work of multiple objects can finally allow us to construct a complex system to solve real problems.
2, Classes and objects
in short, a class is the blueprint and template of an object, and an object is an instance of a class. Although this explanation is a bit like using concepts to explain concepts, we can at least see from this sentence that classes are abstract concepts and objects are concrete things. In the world of object-oriented programming, everything is an object. Objects have attributes and behaviors. Each object is unique, and the object must belong to a class (type). When we extract the static features (attributes) and dynamic features (behaviors) of a large number of objects with common features, we can define something called "class".
in Python, you can use the class keyword to define a class, and then define methods in the class through the previously learned functions, so that you can describe the dynamic characteristics of the object. The code is as follows.
class Student(object): # __ init__ Is a special method used to initialize an object when it is created # Through this method, we can bind the name and age attributes to the student object def __init__(self, name, age): self.name = name self.age = age def study(self, course_name): print('%s I am learning%s.' % (self.name, course_name)) # PEP 8 requires the name of the identifier to be all lowercase and multiple words to be underlined # However, some programmers and companies prefer to use hump naming method (hump identification) def watch_movie(self): if self.age < 18: print('%s Can only watch bear haunt.' % self.name) else: print('%s Watching the island love movie.' % self.name)
note: PEP 8 requires that the name of the identifier be all lowercase and multiple words are underlined, but some programmers and companies prefer to use hump naming method (hump identification)
after we define a class, we can create an object and send messages to the object in the following ways.
def main(): # Create a student object and specify a name and age stu1 = Student('Luo Hao', 38) # Send study message to object stu1.study('Python Programming') # Send a watch to an object_ AV message stu1.watch_movie() stu2 = Student('Da Chui Wang', 15) stu2.study('Ideological and moral character') stu2.watch_movie() if __name__ == '__main__': main()
for the above code, programmers with programming experience in C + +, Java, C # and so on may ask what access rights (also known as visibility) we have bound the name and age attributes of the Student object. Because in many object-oriented programming languages, we usually set the properties of the object to private or protected, which simply means that external access is not allowed, and the methods of the object are usually public, because the public methods are the messages that the object can accept. In Python, there are only two access permissions for attributes and methods, public and private. If you want attributes to be private, you can start with two underscores when naming attributes. The following code can verify this.
class Test: def __init__(self, foo): self.__foo = foo def __bar(self): print(self.__foo) print('__bar') def main(): test = Test('hello') # AttributeError: 'Test' object has no attribute '__bar' test.__bar() # AttributeError: 'Test' object has no attribute '__foo' print(test.__foo) if __name__ == "__main__": main()
however, Python does not strictly guarantee the privacy of private properties or methods from the syntax. It just changes the name of private properties and methods to prevent access to them. In fact, if you know that the rules for changing names can still access them, the following code can verify this. The reason for this setting can be explained by the famous saying "we are all concending results here". Because most programmers think that openness is better than closure, and programmers should be responsible for their own behavior.
class Test: def __init__(self, foo): self.__foo = foo def __bar(self): print(self.__foo) print('__bar') def main(): test = Test('hello') test._Test__bar() print(test._Test__foo) if __name__ == "__main__": main()
in actual development, we do not recommend setting the property to private, because it will make the subclass inaccessible (as will be discussed later). Therefore, most Python programmers will follow a naming convention that is to start the attribute name with a single underscore to indicate that the attribute is protected. Code outside this class should be careful when accessing such attributes. This approach is not a grammatical rule. Properties and methods beginning with a single underscore are still accessible to the outside world, so it is more often a hint or metaphor.
practice:
1. Define a class to describe a digital clock. The clock has three properties: hour, minute and second. Provide an initialization method to initialize three values. Provide the function run to make the time go back one second, provide a function show to print the current time, and call the method every other second in the main function.
2. Define a class to describe points on the plane, provide functions for setting and moving points, and calculate the distance to another point.
reference code:
1. Digital clock
from time import sleep class Clock(object): """Digital clock""" def __init__(self, hour=0, minute=0, second=0): """Initialization method :param hour: Time :param minute: branch :param second: second """ self._hour = hour self._minute = minute self._second = second def run(self): """be in luck""" self._second += 1 if self._second == 60: self._second = 0 self._minute += 1 if self._minute == 60: self._minute = 0 self._hour += 1 if self._hour == 24: self._hour = 0 def show(self): """Display time""" return '%02d:%02d:%02d' % \ (self._hour, self._minute, self._second) def main(): clock = Clock(23, 59, 58) while True: print(clock.show()) sleep(1) clock.run() if __name__ == '__main__': main()
2. Point operation
from math import sqrt class Point(object): def __init__(self, x=0, y=0): """Initialization method :param x: Abscissa :param y: Ordinate """ self.x = x self.y = y def move_to(self, x, y): """Move to the specified location :param x: New abscissa "param y: New ordinate """ self.x = x self.y = y def move_by(self, dx, dy): """Moves the specified increment :param dx: Increment of abscissa "param dy: Increment of ordinate """ self.x += dx self.y += dy def distance_to(self, other): """Calculate the distance from another point :param other: Another point """ dx = self.x - other.x dy = self.y - other.y return sqrt(dx ** 2 + dy ** 2) def __str__(self): return '(%s, %s)' % (str(self.x), str(self.y)) def main(): p1 = Point(3, 5) p2 = Point() print(p1) print(p2) p2.move_by(-1, 2) print(p2) print(p1.distance_to(p2)) if __name__ == '__main__': main()
3, @ property decorator
we discussed the access rights of attributes and methods in Python before. Although we don't recommend setting attributes to private, there are problems if attributes are directly exposed to the outside world. For example, we can't check whether the values assigned to attributes are valid. Our previous suggestion is to name the attribute with a single underscore, which implies that the attribute is protected. Direct external access is not recommended. If you want to access the attribute, you can perform corresponding operations through the getter (accessor) and setter (modifier) methods of the attribute. If you want to do this, you can consider using the @ property wrapper to wrap getter and setter methods, making the access to properties safe and convenient. The code is as follows.
class Person(object): def __init__(self, name, age): self._name = name self._age = age # Accessor - getter method @property def name(self): return self._name # Accessor - getter method @property def age(self): return self._age # Modifier setter method @age.setter def age(self, age): self._age = age def play(self): if self._age <= 16: print('%s Playing flying chess.' % self._name) else: print('%s Playing landlords.' % self._name) def main(): person = Person('Da Chui Wang', 12) person.play() person.age = 22 person.play() # person.name = 'Bai Yuanfang' # AttributeError: can't set attribute if __name__ == '__main__': main()
IV__ slots__ magic
we're here. I don't know if you have realized that Python is a dynamic language. Usually, dynamic languages allow us to bind new properties or methods to objects when the program is running. Of course, we can also unbind the bound properties and methods. However, if we need to restrict objects of custom types to bind only some properties, we can define them in the class__ slots__ Variable to qualify. It should be noted that__ slots__ The restriction of is only valid for the object of the current class and has no effect on the subclass.
class Person(object): # The qualified Person object can only be bound_ name, _age and_ gender attribute __slots__ = ('_name', '_age', '_gender') def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @property def age(self): return self._age @age.setter def age(self, age): self._age = age def play(self): if self._age <= 16: print('%s Playing flying chess.' % self._name) else: print('%s Playing landlords.' % self._name) def main(): person = Person('Da Chui Wang', 22) person.play() person._gender = 'male' # AttributeError: 'Person' object has no attribute '_is_gay' # person._is_gay = True
5, Static methods and class methods
before, all the methods we defined in the class were object methods, that is, these methods were messages sent to objects. In fact, the methods we write in the class do not need to be all object methods. For example, we define a "triangle" class, construct triangles by passing in three side lengths, and provide methods to calculate perimeter and area, but the three side lengths may not be able to construct triangular objects, Therefore, we can write a method to verify whether the three sides can form a triangle. This method is obviously not an object method, because the triangle object has not been created when calling this method (because we don't know whether the three sides can form a triangle), so this method belongs to the triangle class rather than the triangle object. We can use static methods to solve such problems. The code is as follows.
from math import sqrt class Triangle(object): def __init__(self, a, b, c): self._a = a self._b = b self._c = c @staticmethod def is_valid(a, b, c): return a + b > c and b + c > a and a + c > b def perimeter(self): return self._a + self._b + self._c def area(self): half = self.perimeter() / 2 return sqrt(half * (half - self._a) * (half - self._b) * (half - self._c)) def main(): a, b, c = 3, 4, 5 # Both static methods and class methods are called by sending messages to classes if Triangle.is_valid(a, b, c): t = Triangle(a, b, c) print(t.perimeter()) # You can also call the object method by sending a message to the class, but you need to pass in the object receiving the message as a parameter # print(Triangle.perimeter(t)) print(t.area()) # print(Triangle.area(t)) else: print('Cannot form a triangle.') if __name__ == '__main__': main()
similar to static methods, Python can also define class methods in a class. The first parameter of the class method is named cls, which represents the object of information related to the current class (the class itself is also an object, which is also called class metadata object in some places). Through this parameter, we can obtain class related information and create class objects, The code is shown below.
from time import time, localtime, sleep class Clock(object): """Digital clock""" def __init__(self, hour=0, minute=0, second=0): self._hour = hour self._minute = minute self._second = second @classmethod def now(cls): ctime = localtime(time()) return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec) def run(self): """be in luck""" self._second += 1 if self._second == 60: self._second = 0 self._minute += 1 if self._minute == 60: self._minute = 0 self._hour += 1 if self._hour == 24: self._hour = 0 def show(self): """Display time""" return '%02d:%02d:%02d' % \ (self._hour, self._minute, self._second) def main(): # Create objects through class methods and get system time clock = Clock.now() while True: print(clock.show()) sleep(1) clock.run() if __name__ == '__main__': main()
6, Inherit
as we mentioned just now, you can create new classes based on existing classes. One way is to let one class directly inherit properties and methods from another class, so as to reduce repeated code writing. The class that provides inheritance information is called a parent class, also known as a superclass or base class; The inheritance information we get is called a subclass, also known as a derived class or a derived class. Let's take a look at an example of inheritance.
class Person(object): """people""" def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @property def age(self): return self._age @age.setter def age(self, age): self._age = age def play(self): print('%s Playing happily.' % self._name) def watch_av(self): if self._age >= 18: print('%s I'm watching a love action movie.' % self._name) else: print('%s Can only watch bear haunt.' % self._name) class Student(Person): """student""" def __init__(self, name, age, grade): super().__init__(name, age) self._grade = grade @property def grade(self): return self._grade @grade.setter def grade(self, grade): self._grade = grade def study(self, course): print('%s of%s I am learning%s.' % (self._grade, self._name, course)) class Teacher(Person): """teacher""" def __init__(self, name, age, title): super().__init__(name, age) self._title = title @property def title(self): return self._title @title.setter def title(self, title): self._title = title def teach(self, course): print('%s%s Talking%s.' % (self._name, self._title, course)) def main(): stu = Student('Da Chui Wang', 15, 'Junior three') stu.study('mathematics') stu.watch_av() t = Teacher('Luo Hao', 38, 'Brick house') t.teach('Python Programming') t.watch_av() if __name__ == '__main__': main()
after inheriting the method of the parent class, a subclass can give a new implementation version of the existing method of the parent class. This action is called method override. Through method rewriting, we can make the same behavior of the parent class have different implementation versions in the subclass. When we call the method rewritten by the subclass, different subclass objects will show different behaviors. This is poly morphism.
from abc import ABCMeta, abstractmethod class Pet(object, metaclass=ABCMeta): """Pets""" def __init__(self, nickname): self._nickname = nickname @abstractmethod def make_voice(self): """Make a sound""" pass class Dog(Pet): """dog""" def make_voice(self): print('%s: Woof, woof...' % self._nickname) class Cat(Pet): """cat""" def make_voice(self): print('%s: Meow...Meow...' % self._nickname) def main(): pets = [Dog('Wangcai'), Cat('Katie'), Dog('chinese rhubarb')] for pet in pets: pet.make_voice() if __name__ == '__main__': main()
in the above code, we treat the Pet class as an abstract class. The so-called abstract class is a class that cannot create objects. This kind exists specifically for other classes to inherit it. Python does not support abstract classes like Java or C# in terms of syntax, but we can achieve the effect of abstract classes through ABCMeta metaclass and abstractmethod wrapper of abc module. If there are abstract methods in a class, the class cannot be instantiated (create objects). In the above code, the two subclasses of Dog and Cat are respectively used to make in the Pet class_ The voice abstraction method is rewritten and different versions are implemented. When we call this method in the main function, this method shows polymorphic behavior (the same way does different things).
exercise:
1. There are three types of employees in a company, namely department managers, programmers and salespeople. It is necessary to design a salary settlement system to calculate the monthly salary according to the employee information provided. The monthly salary of department managers is fixed at 15000 yuan per month, and the monthly salary of programmers is calculated according to the working hours of the current month, 150 yuan per hour. The salesperson's monthly salary is a base salary of 1200 yuan plus a 5% commission on sales.
from abc import ABCMeta, abstractmethod class Employee(object, metaclass=ABCMeta): """staff""" def __init__(self, name): """ Initialization method :param name: full name """ self._name = name @property def name(self): return self._name @abstractmethod def get_salary(self): """ Get a monthly salary :return: a monthly salary """ pass class Manager(Employee): """division manager""" def get_salary(self): return 15000.0 class Programmer(Employee): """programmer""" def __init__(self, name, working_hour=0): super().__init__(name) self._working_hour = working_hour @property def working_hour(self): return self._working_hour @working_hour.setter def working_hour(self, working_hour): self._working_hour = working_hour if working_hour > 0 else 0 def get_salary(self): return 150.0 * self._working_hour class Salesman(Employee): """salesperson""" def __init__(self, name, sales=0): super().__init__(name) self._sales = sales @property def sales(self): return self._sales @sales.setter def sales(self, sales): self._sales = sales if sales > 0 else 0 def get_salary(self): return 1200.0 + self._sales * 0.05 def main(): emps = [ Manager('Liu Bei'), Programmer('Zhuge Liang'), Manager('Cao Cao'), Salesman('Xun Yu'), Salesman('Lv Bu'), Programmer('Zhang Liao'), Programmer('Zhao Yun') ] for emp in emps: if isinstance(emp, Programmer): emp.working_hour = int(input('Please enter%s Working hours of this month: ' % emp.name)) elif isinstance(emp, Salesman): emp.sales = float(input('Please enter%s Current month sales: ' % emp.name)) # Also receive get_salary this message, but different employees show different behaviors (polymorphism) print('%s The salary this month is: ¥%s element' % (emp.name, emp.get_salary())) if __name__ == '__main__': main()