Python Basics (week 7)

Posted by slands10 on Wed, 26 Jan 2022 17:37:10 +0100

catalogue

1, Decorator supplement

Decorator belt parameters

2, Object oriented

1. Object oriented and process oriented

2. Class and object

3. Object oriented basic syntax

(1) Create class (method only)

(2) Create object

(3) Introduction to initialization method

(4)__ del__ Method introduction

(5)__ str__ method

4. Object oriented encapsulation

5. Object oriented private attributes and private methods

6. Object oriented inheritance

Use inheritance development:

Method override

Multiple inheritance

7. Polymorphism

1, Decorator supplement

Decorator belt parameters

Let's write a decorator with parameters first, and then explain it

def func_arg(name):
    def func_out(func):
        def wrapped_func():
            print('This is a decorator')
            print('Executing decorated function...')
            func()
            print('Outputting parameters for decorator...')
            print(name)

        return wrapped_func

    return func_out


@func_arg('world')
def f():
    print('hello')


f()
'''
This is a decorator
 Executing decorated function...
hello
 Outputting parameters for decorator...
world
'''

1. Execute @ func_arg('world '), call func_arg function and pass' world 'as a parameter to name. Enter func after calling_ Arg executes programs from top to bottom internally.

2. Execute func_ Def func inside ARG_ Out (func): defines func_outer function, func_ The out function is loaded into memory

3. Execute func_ Return func inside ARG_ Out, func_ A reference to the out function is returned to func_ Caller of Arg function: @ func_arg('world '), so the logic of the code becomes

def func_out(func):
    def wrapped_func():
        print('This is a decorator')
        print('Executing decorated function...')
        func()
        print('Outputting parameters for decorator...')
        print(name)    # The value of name is already in memory

    return wrapped_func


@func_out
def f():
    print('hello')


f()

Here is the normal decorator we are familiar with

2, Object oriented

1. Object oriented and process oriented

Process oriented:

Process oriented is different from object-oriented. Process oriented analyzes the steps needed to solve the problem, and then uses functions to realize these steps step by step. When using, it can be called one by one.  

object-oriented:

Object oriented is to decompose the problem transaction into various objects. The purpose of establishing objects is not to complete a step, but to describe the behavior of something in the whole problem-solving step.

difference:

In short: the program written in the process oriented method is an egg fried rice, while the program written in the object-oriented method is a cover rice. The so-called cover rice is to pour a cover dish on the rice. You can pour whatever dish you like. I think this metaphor is more appropriate.

I don't know the details of fried rice with eggs, because I haven't been a cook and can't cook, but the last process must be to mix rice and eggs and stir well. If you want a braised meat covered rice, you will be watered with a braised meat; If you want a green pepper potato to water the rice, pour a green pepper potato shred.

The advantage of fried rice with eggs is that it tastes even and tastes delicious. If it happens that you don't like eggs and only vegetables, the only way is to pour them all out and make a new fried rice with vegetables. It's not so much trouble to cover the rice. You just need to remove the cover and replace it with a cover. The disadvantage of covered rice is that it tastes uneven. It may not be as fragrant as egg fried rice.

Is it better to stir fry rice with eggs or water rice? In fact, such questions are difficult to answer. If you have to compare up and down, you must set a scene, otherwise you can only say that they have their own strengths. Well, from the restaurant point of view, cooking covered rice obviously has more advantages than egg fried rice. He can combine as many combinations as he wants without wasting.

The advantage of covered rice is the separation of "food" and "rice", which improves the flexibility of making covered rice. If you are not satisfied with the food, change the food. If you are not satisfied with the food, change the food. In the professional term of software engineering, "maintainability" is better, and the coupling degree of "rice" and "dish" is relatively low. Egg fried rice mixes "egg" and "rice". It is difficult to change any of "egg" and "rice", and the coupling degree is very high, so that the "maintainability" is poor. One of the goals of software engineering is maintainability, which is mainly reflected in three aspects: comprehensibility, testability and modifiability. One of the benefits of object-oriented is that it significantly improves the maintainability of software system.

2. Class and object

Class: something with the same characteristics (properties in programming) and behavior (Methods in programming)

This kind of popular understanding can be the drawings and templates for manufacturing aircraft (can not be used directly)

Object: the specific existing things created by the class (which can be used directly), and the properties and methods of which class are created

When we get a requirement, we should first analyze which classes need to be created: for example, to develop a plant vs. zombie game, the main classes are: plant class and zombie class, and then analyze the attributes (i.e. what are the same characteristics of this class) and methods (i.e. what are the same behaviors of this class)

Note: the naming of the class should meet the big hump naming method: the first letter of each word should be capitalized

3. Object oriented basic syntax

(1) Create class (method only)

class Class name:
    
    def Method 1(self, parameter list):
        pass

    def Method 2(self, parameter list):
        pass

Self is a required parameter, and self represents the object itself

(2) Create object

Object name = Class name()

Example: the kitten likes to eat fish, and the kitten is drinking water

class Cat:

    def eat(self):
        print('The kitten is eating fish')

    def drink(self):
        print('The kitten is drinking water')


little_cat = Cat()
little_cat.eat()  # The kitten is eating fish
little_cat.drink()  # The kitten is drinking water

If the kitten has a name, Tom, as if his name is an attribute, we can modify the code at this time

class Cat:

    def eat(self):
        print(f'{self.name}Eating fish')

    def drink(self):
        print(f'{self.name}Drinking water')


little_cat = Cat()
little_cat.name = 'Tom'
little_cat.eat()  # Tom is eating fish
little_cat.drink()  # Tom is drinking water

The above is to add attributes to the object outside the class. If the code is modified to the following, it will report an error. Therefore, adding attributes outside the class is not recommended

class Cat:

    def eat(self):
        print(f'{self.name}Eating fish')

    def drink(self):
        print(f'{self.name}Drinking water')


little_cat = Cat()
little_cat.eat() 
little_cat.drink()  
little_cat.name = 'Tom'

(3) Introduction to initialization method

class Cat:
    def __init__(self):
        print('This is an initialization method')

    def eat(self):
        print(f'{self.name}Eating fish')

    def drink(self):
        print(f'{self.name}Drinking water')


little_cat = Cat()  # This is an initialization method

The initialization method is automatically called when the object is created:__ init__ method

Therefore, we can add properties to the class by passing parameters to the initialization method, so that its properties will be automatically initialized when the object is created

class Cat:
    def __init__(self,name):
     # Property name of object = parameter name
        self.name = name

    def eat(self):
        print(f'{self.name}Eating fish')

    def drink(self):
        print(f'{self.name}Drinking water')


little_cat = Cat('Tom')  
little_cat.eat()  # Tom is eating fish
little_cat.drink()  # Tom is drinking water

big_cat = Cat('Jerry')
big_cat.eat()  # Jerry is eating fish
big_cat.drink()  # Jerry is drinking water

(4)__ del__ Method introduction

This method will be called automatically before the object is destroyed from the internal address (it can be understood as the last contribution before death)

class Cat:
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(f'{self.name}Eating fish')

    def drink(self):
        print(f'{self.name}Drinking water')

    def __del__(self):
        print(f'{self.name}Run away')


little_cat = Cat('Tom')
little_cat.eat()  # Tom is eating fish
little_cat.drink()  # Tom is drinking water

big_cat = Cat('Jerry')
big_cat.eat()  # Jerry is eating fish
big_cat.drink()  # Jerry is drinking water

print('*' * 50)
'''
Tom Eating fish
Tom Drinking water
Jerry Eating fish
Jerry Drinking water
**************************************************
Tom Run away
Jerry Run away
'''

We found that when the program is finished, big_cat and little_cat is automatically destroyed and executed__ del__ method

We can also delete it manually

class Cat:
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(f'{self.name}Eating fish')

    def drink(self):
        print(f'{self.name}Drinking water')

    def __del__(self):
        print(f'{self.name}Run away')


little_cat = Cat('Tom')
little_cat.eat()  # Tom is eating fish
little_cat.drink()  # Tom is drinking water

big_cat = Cat('Jerry')
big_cat.eat()  # Jerry is eating fish
big_cat.drink()  # Jerry is drinking water
del little_cat
print('*' * 50)
'''
Tom Eating fish
Tom Drinking water
Jerry Eating fish
Jerry Drinking water
Tom Run away
**************************************************
Jerry Run away
'''

We manually deleted little before printing *_ Cat variable, he executes it__ del__ Method, big_cat is automatically destroyed after the program is executed__ del__ method

(5)__ str__ method

class Cat:
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(f'{self.name}Eating fish')

    def drink(self):
        print(f'{self.name}Drinking water')

    def __del__(self):
        print(f'{self.name}Run away')


little_cat = Cat('Tom')
print(little_cat)  # <__main__.Cat object at 0x000001832B989190>
little_cat.eat()  # Tom is eating fish
little_cat.drink()  # Tom is drinking water

We're joining__ str__ Method, print the variable name of the object, and you will find that the output is the address of the object in memory

class Cat:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return f'The cat's name is{self.name}'

    def eat(self):
        print(f'{self.name}Eating fish')

    def drink(self):
        print(f'{self.name}Drinking water')

    def __del__(self):
        print(f'{self.name}Run away')


little_cat = Cat('Tom')
print(little_cat)  # The cat's name is Tom
little_cat.eat()  # Tom is eating fish
little_cat.drink()  # Tom is drinking water

When we set__ str__ Method, and then print the variable name of the object. The output is__ str__ Contents of return in method

4. Object oriented encapsulation

Demand: Xiao Ming weighs 75kg, loses 0.5kg every time he runs, and gains 1kg every time he eats

class Person:

    def __init__(self, name, weight):
        self.name = name
        self.weight = weight

    def __str__(self):
        return f'I am{self.name},My weight is{self.weight}'

    def run(self):
        # One call, weight loss 0.5
        print('run...')
        self.weight -= 0.5

    def eat(self):
        # Call once, weight gain 1
        print('eat...')
        self.weight += 1

    def __del__(self):
        print(f'{self.name}What's your weight now{self.weight}')


xiaoming = Person('Xiao Ming', 75)
xiaoming.run()  # run...
xiaoming.run()  # run...
xiaoming.eat()  # eat
print(xiaoming)  # I'm Xiao Ming. My weight is 75.0
xiaoming.run()  # run...
xiaoming.eat()  # eat
xiaoming.eat()  # eat
xiaoming.eat()  # eat
print('*' * 50)
# Xiao Ming now weighs 77.5

Demand: the House has House type, total area and furniture name list. There is no furniture in the new House. The furniture (HouseItem) has furniture name and floor area, of which bed covers an area of 4 square meters, chest covers an area of 2 square meters and table covers an area of 2.5 square meters. Add the above three pieces of furniture to the House. When printing the House, it is required to output the House type, Total area, remaining area, furniture name list

analysis:

House class: attribute: area, house type, furniture name list, remaining area} method: initialization method, str method, add furniture method

HouseItem class: attribute: name, method: initialization method, str method

Because furniture is used in the House class, develop the HouseItem class first

class HouseItem:

    def __init__(self, name, area):
        """
        :param name: Furniture name
        :param area: area covered
        """
        self.name = name
        self.area = area

    def __str__(self):
        return '[%s] The floor area is %.2f square metre' % (self.name, self.area)


# Create furniture
bed = HouseItem('Simmons', 4)
chest = HouseItem('wardrobe', 2)
table = HouseItem('table', 2.5)
print(bed)
print(chest)
print(table)


class House:

    def __init__(self, house_type, area):
        """
        :param house_type: House type
        :param area: total area
        """
        self.house_type = house_type
        self.area = area
        # The remaining area is consistent with the total area by default
        self.free_area = area
        # Furniture name list (no furniture by default)
        self.item_list = []

    def __str__(self):
        return ("House type:%s\n total area:%.2f square metre[Remaining area:%.2f square metre]\n Furniture name:%s"
                % (self.house_type, self.area,
                   self.free_area, self.item_list))

    def add_item(self, item):
        print("To add%s" % item)

        # 1. Judge whether the area of furniture is greater than the remaining area
        if item.area > self.free_area:
            print("To add%s The area is too large to add" % item.name)
            return

        # 2. Add the name of the furniture to the list
        self.item_list.append(item.name)

        # 3. Calculate the remaining area
        self.free_area -= item.area


my_home = House("two bedrooms ", 60)
my_home.add_item(bed)
my_home.add_item(chest)
my_home.add_item(table)

print(my_home)

5. Object oriented private attributes and private methods

Some properties or methods of an object only want to be used inside the object, not accessed outside

Definition: add two underscores before the property name or method name

class Girl:

    def __init__(self, name, age):
        self.name = name
        # Define private properties
        self.__age = age

    # Define private methods
    def __secret(self):
        print(f'{self.name}What is your age{self.__age}')


xiaomei = Girl('Xiaomei', 20)
print(xiaomei.name)  # Xiaomei
print(xiaomei.__age)  # report errors

xiaomei = Girl('Xiaomei', 20)
xiaomei.__secret()    # report errors

We can see that the output name attribute can be output normally, but we have clearly defined it__ age attribute, but an error is reported in the output

class Girl:

    def __init__(self, name, age):
        self.name = name
        # Define private properties
        self.__age = age

    # Define private methods
    def __secret(self):
        print(f'{self.name}What is your age{self.__age}')


xiaomei = Girl('Xiaomei', 20)
xiaomei.__secret()    # report errors

Similarly, an error will be reported when calling a private method

However, there is no real private property in python, and we still have a way to access private properties and private methods

class Girl:

    def __init__(self, name, age):
        self.name = name
        # Define private properties
        self.__age = age

    # Define private methods
    def __secret(self):
        print(f'{self.name}What is your age{self.__age}')


xiaomei = Girl('Xiaomei', 20)
print(xiaomei._Girl__age)  # 20

We're calling__ Add before age attribute_ Class name, you can use private properties

class Girl:

    def __init__(self, name, age):
        self.name = name
        # Define private properties
        self.__age = age

    # Define private methods
    def __secret(self):
        print(f'{self.name}What is your age{self.__age}')


xiaomei = Girl('Xiaomei', 20)
xiaomei._Girl__secret()  # Xiaomei's age is 20

We're calling__ Add before the secret method_ Class name, you can call private methods

6. Object oriented inheritance

Inheritance: a subclass has all the properties and methods of its parent class

class Animal:
    def eat(self):
        print('eat')

    def sleep(self):
        print('sleep')


class Dog:
    def eat(self):
        print('eat')

    def sleep(self):
        print('sleep')


dog = Dog()
dog.eat()  # eat
dog.sleep()  # sleep

Dogs belong to animals. Animals can eat and sleep, and dogs can eat and sleep. Since dogs belong to animals, is there a way not to redefine a method of eating and sleeping in dogs (to avoid code redundancy)? This requires the use of inheritance

Use inheritance development:

class Animal:
    def eat(self):
        print('eat')

    def sleep(self):
        print('sleep')


# Subclass (inherited parent)
class Dog(Animal):
    # You can add subclass specific methods
    def bark(self):
        print('bark')


dog = Dog()
dog.eat()  # eat
dog.sleep()  # sleep
dog.bark()  # bark

It can be seen that we do not define eat and sleep methods in dogs that inherit Animal classes, but we can call eat and sleep methods in the parent class (Animal class)

class Animal:
    def eat(self):
        print('eat')

    def sleep(self):
        print('sleep')


# Subclass (inherited parent)
class Dog(Animal):
    # You can add subclass specific methods
    def bark(self):
        print('bark')


class XiaoTianQuan(Dog):
    def fly(self):
        print('fly')


dog = XiaoTianQuan()
dog.eat()  # eat
dog.sleep()  # sleep
dog.bark()  # bark
dog.fly()  # fly

We also defined a dog class to inherit from dogs, while dogs inherit from animals. We found that the dog class object can call the methods of the parent class, indicating that inheritance is transitive

Method override

What should we do when the methods in the parent class are not satisfied with the requirements of the child class?

1. Method of overriding parent class

class Dog(Animal):
    # You can add subclass specific methods
    def bark(self):
        print('bark')


class XiaoTianQuan(Dog):
    def fly(self):
        print('fly')

For example, the barking of a dog is different from that of a dog. What should we do?

class Dog():
    # You can add subclass specific methods
    def bark(self):
        print('bark')


class XiaoTianQuan(Dog):
    def fly(self):
        print('fly')

    def bark(self):
        print('Howling dog bark')


dog = XiaoTianQuan()
dog.bark()  # Barker's Barker

We can define another bark method in the howling Dog class when executing dog When barking (), it will first find the barking method of the subclass. If it is found, it will execute the barking method of the subclass. If the subclass does not find the barking method of the parent class. This is the first method of method Rewriting: overriding the method of the parent class

2. Extend parent method

If the methods of the parent class cannot fully meet the requirements (only part of the requirements can be met), the methods of the parent class must be extended in the child class. How to implement this?

class Dog():
    # You can add subclass specific methods
    def bark(self):
        print('bark')


class XiaoTianQuan(Dog):
    def fly(self):
        print('fly')

    def bark(self):
        super().bark()
        print('Howling dog bark')


dog = XiaoTianQuan()
dog.bark()  
'''
bark
 Howling dog bark
'''

A bark method is also defined in the subclass, using super() The parent method name () calls the parent class method name, and then increases the unique requirement of the subclass. In the end, after calling the bark method after the object is created, it calls the bark method that extends the parent class bark in the subclass.

Note: when there are private methods and properties in the parent class, the child class cannot directly inherit the private properties and methods of the parent class. If you want to use them, you can use the methods described above.

Multiple inheritance

If a subclass inherits from more than one parent class, it is called multi inheritance

class A(object):
    def test(self):
        print('A---test')

    def demo(self):
        print('A---demo')


class B(object):
    def demo(self):
        print("B---demo")

    def test(self):
        print('B---test')


class C(B, A):
    pass


c = C()
c.test()   # B---test 
c.demo()   # B---demo

Note: when there are methods with the same name in multiple parent classes inherited by the child class, and we call this method, the method of the first parent class in parentheses will be executed first

7. Polymorphism

Different subclasses call the same parent method to produce different results, which is called polymorphism

prerequisite:

1. Inheritance: polymorphism must occur between subclasses and parents;

2. Override: the subclass overrides the method of the parent class.

class WhoSay:
    def say(self,who):
        who.say()
class CLanguage:
    def say(self):
        print("Called is Clanguage Class say method")
class CPython(CLanguage):
    def say(self):
        print("Called is CPython Class say method")
class CLinux(CLanguage):
    def say(self):
        print("Called is CLinux Class say method")
a = WhoSay()
#Call the say() method of the CLanguage class
a.say(CLanguage())
#Call the say() method of CPython class
a.say(CPython())
#Call the say() method of the CLinux class
a.say(CLinux())
'''
Called is Clanguage Class say method
 Called is CPython Class say method
 Called is CLinux Class say method
'''

Topics: Python