catalogue
Creating and working with objects
Static methods and class methods
Define 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. In this way, 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)
Creating and working with objects
After we define a class, we can create an object and send messages to the object in the following way.
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()
Object oriented pillar
Object oriented has three pillars: encapsulation, inheritance and polymorphism. The latter two concepts will be described in detail in the next chapter. Let's talk about encapsulation first. My own understanding of encapsulation is to "hide all implementation details that can be hidden, and only expose (provide) simple programming interfaces to the outside world". The method we define in the class actually encapsulates the data and operations on the data. After we create the object, we only need to send a message to the object (call the method) to execute the code in the method, that is, we only need to know the name of the method and the passed in parameters (external view of the method), You don't need to know the implementation details inside the method (the internal view of the method).
@property decorator
Previously, we discussed the access rights of attributes and methods in Python. Although we do not recommend setting attributes to private, there are problems if attributes are directly exposed to the outside world. For example, we have no way to 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()
__ slots__ magic
At this point, I don't know if you have realized that Python is a language 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
Static methods and class methods
Previously, the methods we defined in the class are all object methods, that is, these methods are 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()
Relationships between classes
In short, there are three relationships between classes: is-a, has-a and use-a.
- is-a relationship is also called inheritance or generalization. For example, the relationship between students and people, the relationship between mobile phones and electronic products all belong to inheritance.
- has-a relationship is usually called Association, such as the relationship between departments and employees, and the relationship between cars and engines; If an association relationship is a whole or part Association, we call it an aggregation relationship; If the whole is further responsible for the life cycle of parts (the whole and parts are inseparable and die at the same time), then this is the strongest correlation, which we call synthetic relationship.
- The use-a relationship is usually called dependency. For example, if the driver has a driving behavior (method), and the (parameter) uses the car, the relationship between the driver and the car is dependency.
Inheritance and polymorphism
Just now we mentioned that 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. In addition to inheriting the properties and methods provided by the parent class, subclasses can also define their own unique properties and methods. Therefore, subclasses have more capabilities than parent classes. In actual development, we often replace a parent object with a subclass object, which is a common behavior in object-oriented programming. The corresponding principle is called Richter substitution principle . 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 a subclass inherits the method of the parent class, it 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).
https://github.com/jackfrued/Python-100-Dayshttps://github.com/jackfrued/Python-100-Days