Python - object oriented - Day08

Posted by DarrenL on Fri, 19 Nov 2021 11:32:28 +0100

Object oriented programming and functional programming (process oriented programming) are both methods of programming, but there are some differences.

Process oriented programming:

1. Import various external libraries
2. Design various global variables
3. Write a function to complete a function
4. Write a function to complete a function
5. Write a function to complete a function
6. Write a function to complete a function
7. Write a function to complete a function
8. ......
9. Write one main Function as program entry

In multi-function programs, many important data are placed in the global data area so that they can be accessed by all functions. Each function can have its own local data. Some function codes are encapsulated in the function. In the future, there is no need to write repeatedly, just call the function. From the perspective of the organization form of the code, it is the code from top to bottom according to the business logic.

Object oriented programming:

1. Import various external libraries
2. Design various global variables
3. Decide which class you want
4. Provide a complete set of operations for each class
5. Explicitly use inheritance to express common ground between different classes
6. Decide whether to write one as needed main Function as program entry

In object-oriented programming, functions and variables are further encapsulated into classes. Classes are the basic elements of programs. They closely connect data and operations, and protect data from accidental changes by external functions. Class and class instance (also known as object) are the core concepts of object-oriented, which are fundamentally different from process oriented programming and functional programming.

It doesn't have to use object-oriented programming. It depends on how your program is designed to be convenient, but at present, it is basically using object-oriented programming.

Basic usage of class

Object oriented is defined by defining class classes. In this way, object-oriented programming only uses class classes, which have the functions of encapsulation and inheritance, and can also construct parameters to be passed in for easy control.

Case 1

import sys
import time
reload(sys)
sys.setdefaultencoding('utf-8')

class studetn:
    # Define a class named studetn
    def __init__(self,idx):
    # Define the initialization structure. init is used here. There are other attributes such as reversed and iter
        self.idx=idx
        # Initialize variables to facilitate inheritance
    def runx(self):
    # Define the run function and inherit variables from it
        print self.idx
        # Print out the value of idx, or do some other processing
        time.sleep(1)
a=studetn('a')
a.runx()
# This is a call to a class. You must remember how to use the class. First pass in parameters and assign the class to a variable a
# Then call the function defined below this class.

Since there is a big definition of object-oriented programming for some professional terms and concepts, it is natural to match some big concepts.

  1. Class: used to describe a collection of objects with the same properties and methods. It defines the properties and methods common to each object in the collection. The objects are called instances of classes.
  2. Instance: also known as object. Through the initialization method defined by the class, give specific values and become a "flesh and blood entity".
  3. Instantiation: the process or operation of creating an instance of a class.
  4. Instance variable: a variable defined in an instance. It only works on the current instance.
  5. Class variables: class variables are variables that are public to all instances. Class variables are defined in the class, but outside the method body.
  6. Data member: a general term for class variables, instance variables, methods, class methods, static methods, attributes, etc.
  7. Method: a function defined in a class.
  8. Static method: a method that can be executed by a class without instantiation
  9. Class method: a class method is a method that operates on the class itself as an object.
  10. Method Rewriting: if the method inherited from the parent class cannot meet the needs of the child class, the method of the parent class can be rewritten. This process is also called override.
  11. Encapsulation: wrap the internal implementation, be transparent to the outside, and provide a mechanism for api interface calls
  12. Inheritance: that is, a derived class inherits the variables and methods of the parent class.
  13. Polymorphism: it is handled in different ways according to different object types.

Classes and instances

# -*- coding: utf-8 -*-
# @Time    : 2018/5/3 0003 17:02
# @Author  : Langzi
# @Blog    : www.langzi.fun
# @File: object oriented 2.py
# @Software: PyCharm
import sys
import time
import requests
reload(sys)
sys.setdefaultencoding('utf-8')

class cc:
    ccc = 'ccc'
    # cc is the class name. If you want to inherit from other classes, class cc(threading) means to inherit from threading
    def __init__(self,a,b,c):
        self.a=a
        self.b=b
        self.c=c
        # The process of defining a construct is instantiation
    def runx(self):
        print self.a*10
        print self.b*5
        print self.c*2
    def runy(self):
        print requests.get('http://www.langzi.fun').headers
e = cc('AAA','CCC','EEE')
e.runx()
e.runy()
# These two are the methods in the calling class
print e.c
#Instance variables refer to the variables owned by the instance itself. The variables of each instance are different in memory.
print e.ccc
#Class variable, find the defined variable in the class.

Three methods of calling classes

Example method

# -*- coding: utf-8 -*-
# @Time    : 2018/5/3 0003 17:16
# @Author  : Langzi
# @Blog    : www.langzi.fun
# @File: object oriented 3.py
# @Software: PyCharm
import sys
import time
import requests
reload(sys)
sys.setdefaultencoding('utf-8')

class dd:
    def __init__(self,url):
        self.url=url
    def runx(self):
        print requests.get(self.url).status_code

a = dd('http://www.langzi.fun')
a.runx()
# This calling method is the instance method

Static method

Static methods are called by classes without default parameters. Remove self from the instance method parameter, and then add @ staticmethod above the method definition to become a static method. It belongs to class and has nothing to do with instances. It is recommended to use only the calling method of class name. Static method. (although it can also be called by using instance name. Static method)

# -*- coding: utf-8 -*-
# @Time    : 2018/5/3 0003 17:21
# @Author  : Langzi
# @Blog    : www.langzi.fun
# @File: object oriented 4.py
# @Software: PyCharm
import sys
import requests
reload(sys)
sys.setdefaultencoding('utf-8')
class ff:
    @staticmethod
    def runx():
        print requests.get('http://www.langzi.fun').status_code
ff.runx()
#Here, you directly call the variables of the class and the methods that run only in the class but not in the instance

There are often some functions related to classes, but static methods need to be used when running without the participation of instances and classes. For example, static methods can be used to change environment variables or modify the properties of other classes. This situation can be solved directly with functions, but it will also spread the code inside the class and cause maintenance difficulties.

Class method

Class methods are called by the class, decorated with @ classmethod, and at least one cls (referring to the class itself, similar to self) parameter is passed in. When a class method is executed, the class calling the method is automatically assigned to cls. It is recommended to use only the class name and the calling method of class methods. (although it can also be called by instance name. Class method)

Actual case

If you want to construct a class, accept a website and its status code, and then print it out. Like this:

import sys
import requests
reload(sys)
sys.setdefaultencoding('utf-8')
class gg:
    def __init__(self,url,stat):
        self.url=url
        self.stat=stat
    def outer(self):
        print self.url
        print self.stat
a = gg('langzi',200)
a.outer()

This is to use the instance method. Although it can be implemented, sometimes the passed parameters are not in the format of ('langzi ', 200), but in the format of ('langzi-200'). What should we do? First, we need to split this, but it is very troublesome to use the instance method. At this time, we can use the class method.

# -*- coding: utf-8 -*-
# @Time    : 2018/5/3 0003 17:27
# @Author  : Langzi
# @Blog    : www.langzi.fun
# @File: object oriented 5.py
# @Software: PyCharm
import sys
import requests
reload(sys)
sys.setdefaultencoding('utf-8')
class gg:
    url = 0
    stat = 0
    # Because new variables will be passed in after using classmethod, you need to define class variables first
    def __init__(self,url=0,stat=0):
    # Here, the constructor is defined as normal
        self.url=url
        self.stat=stat
    @classmethod
    # Decorator, immediately execute the following function
    def split(cls,info):
        # This function accepts two parameters. The default cls is the init function of this class, and info is passed in from the outside
        url,stat=map(str,info.split('-'))
        # This is converted to a formatted structure
        data = cls(url,stat)
        # Then execute the first method of the class. The class constructor needs to pass in two parameters, so two parameters are passed in
        return data
        # Here, the function result is returned directly
    def outer(self):
        print self.url
        print self.stat

r = gg.split(('langzi-200'))
r.outer()
# Here is to call class methods, just like calling instance methods

Class properties

encapsulation

Encapsulation refers to placing data and the implementation code of specific operations inside an object, which cannot be accessed externally. The method of the class must be called before it can be started.

case

class cc:
    ccc = 'ccc'
    # cc is the class name. If you want to inherit from other classes, class cc(threading) means to inherit from threading
    def __init__(self,a,b,c):
        self.a=a
        self.b=b
        self.c=c
print e.ccc
#Class variable, find the defined variable in the class.
print ccc
# An error will be reported here. This is encapsulation. The same is true for functions in classes.

inherit

When we define a class, we can inherit from an existing class. The new class is called a Subclass, and the inherited class is called a Base class, a parent class, or a superclass (Base class, Super class).
For example, we have written a class named Animal, which has a run() method to print directly:

class Animal(object):
    def run(self):
        print 'Animal is running...'

When we need to write Dog and Cat classes, we can directly inherit from Animal class:

class Dog(Animal):
    pass
class Cat(Animal):
    pass

What are the benefits of inheritance? The biggest advantage is that the subclass obtains all the functions of the parent class. Since Animial implements the run() method, Dog and Cat, as its subclasses, automatically own the run() method without doing anything:

dog = Dog()
dog.run()
cat = Cat()
cat.run()

When the same run() method exists in both the subclass and the parent class, we say that the run() of the subclass overrides the run() of the parent class. When the code runs, the run() of the subclass will always be called. In this way, we gain another benefit of inheritance: polymorphism.

polymorphic

To understand the benefits of polymorphism, we need to write another function that accepts an Animal variable:

def run_twice(animal):
    animal.run()
    animal.run()

When we pass in an instance of Animal, run_twice() prints out:

run_twice(Animal())
Operation results:
Animal is running...
Animal is running...

When we pass in an instance of Dog, run_twice() prints out:

run_twice(Dog())
Operation results:
Dog is running...
Dog is running...

When we pass in an instance of Cat, run_twice() prints out:

run_twice(Cat())
Operation results:
Cat is running...
Cat is running...

It doesn't seem interesting, but think about it carefully. Now, if we define another Tortoise type, it also derives from Animal:

class Tortoise(Animal):
    def run(self):
        print 'Tortoise is running slowly...'

When we call run_ When twice(), an instance of Tortoise is passed in:

run_twice(Tortoise())
Operation results:
Tortoise is running slowly...
Tortoise is running slowly...

You'll find that adding a subclass of Animal doesn't have to run_ In fact, any function or method that relies on Animal as a parameter can run normally without modification. The reason is polymorphism.

The advantage of polymorphism is that when we need to pass in Dog, Cat and Tortoise, we only need to receive the Animal type, because Dog, Cat and Tortoise are all Animal types, and then operate according to the Animal type. Since an Animal type has a run() method, any type passed in, as long as it is an Animal class or subclass, will automatically call the run() method of the actual type, which means polymorphism:

For a variable, we only need to know that it is an Animal type, and we can safely call the run() method without knowing its subtype. The specifically called run() method acts on an Animal, Dog, Cat or Tortoise object, which is determined by the exact type of the object at runtime. This is the real power of polymorphism: the caller only calls, regardless of details, When we add a subclass of Animal, we just need to ensure that the run() method is written correctly, regardless of how the original code is called. This is the famous "opening and closing" principle:

Open to extensions: allow adding new Animal subclasses;
Closed to modification: it is not necessary to modify run that depends on Animal type_ Functions such as twice().
Summary: inheritance can directly take all the functions of the parent class, so there is no need to start from scratch. Subclasses only need to add their own unique methods, or they can overwrite the methods that are not suitable for the parent class;
With inheritance, there can be polymorphism. When calling class instance methods, try to treat variables as parent types, so that all child class types can be received normally;
The old method of defining Python classes allows you not to inherit from object classes, but this programming method is seriously not recommended. At any time, if there is no suitable class to inherit, it inherits from the object class.

Magic method

In addition to init, ITER and reverse methods are mentioned above. Here we will talk in detail about other methods besides init initialization.

__init__ :      Constructor, called when the object is generated
__del__ :       Destructor, used when releasing an object
__repr__ :      Printing, converting
__setitem__ :   Assignment by index
__getitem__:    Get value by index
__len__:        Get length
__cmp__:        Comparison operation
__call__:       call
__add__:        Addition operation
__sub__:        Subtraction operation
__mul__:        Multiplication operation
__div__:        Division operation
__mod__:        Remainder operation
__pow__:        power

Specific use

1. doc

Descriptive documents and information. Python is self built without customization.

class Foo:
    """ Description class information, which can be collected automatically """
    def func(self):
        pass
# Print a description document for the class 
print(Foo.__doc__)

2. init()

Instantiation method. When an instance is created through a class, execution is automatically triggered.

class Foo:
    def __init__(self, name):
        self.name = name
        self.age = 18
obj = Foo(jack') # Automatically execute in class__ init__  method

3. module__ And__ class

Module indicates which module the object of the current operation belongs to.
Class indicates which class the object of the current operation belongs to.
These two are also built-in in Python and do not need to be customized.

class Foo:
    pass
obj = Foo()
print(obj.__module__)
print(obj.__class__)
Operation results:
main

4. del()

Destruct method, which is automatically triggered when the object is released in memory.

Note: this method generally does not need to be customized, because Python has its own memory allocation and release mechanism, unless you need to specify some actions when releasing. The call of the destructor is automatically triggered by the interpreter during garbage collection.

class Foo:
    def __del__(self):
        print("I was recycled!")

obj = Foo()
del obj

5. call()

If the method is written for a class, the method can be called by placing parentheses after the instance of the class.

Note: the execution of the construction method is executed by the class with parentheses, that is, object = class name (). For the call() method, it is triggered by the parentheses after the object, that is, object () or class () ()

class Foo:
    def __init__(self):
        pass
    def __call__(self, *args, **kwargs):
        print('__call__')
obj = Foo()     # Execute__ init__
obj()       # Execute__ call__

You can test with Python's built-in callable() function to determine whether an object can be executed.

callable(Student())

Operation results:

True

6. dict

List all members in the class or object! A very important and useful attribute, built by Python, does not need to be defined by the user.

class Province:
    country = 'China'
    def __init__(self, name, count):
        self.name = name
        self.count = count
    def func(self, *args, **kwargs):
        print('func')
# Gets the member of the class
print(Province.__dict__)
# Gets the member of object obj1 
obj1 = Province('HeBei',10000)
print(obj1.__dict__)
# Gets the member of object obj2 
obj2 = Province('HeNan', 3888)
print(obj2.__dict__)

7. str()

If the str() method is defined in a class, the return value of the method will be output by default when printing the object. This is also a very important method, which needs to be defined by the user.  

The following classes have no str() method defined, and the print result is:

class Foo:
    pass
obj = Foo()
print(obj)
Defined__str__()Method, the print result is:'jack'. 
class Foo:
    def __str__(self):
        return 'jack'
obj = Foo()
print(obj)

8,getitem__(),_setitem_(),__delitem()

We have seen the routine of taking value, assigning value and deleting the "three swordsmen" many times in Python, such as the @ property decorator in front.

In Python, the identifier is followed by parentheses, which usually represents the meaning of executing or calling a method. Brackets [] are added after the identifier, which usually represents the meaning of value. Python designs three special members: getitem(), setitem(), and delitem(), which are used to perform actions related to brackets. They represent value taking, value assignment and data deletion respectively.

That is, the following operations:

a = identifier [] :    implement__getitem__method
 identifier [] = a  :    implement__setitem__method
del identifier [] :    implement__delitem__method

If a class defines these three magic methods at the same time, the behavior of the instance of this class looks like a dictionary, as shown in the following example:

class Foo:
    def __getitem__(self, key):
        print('__getitem__',key)
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
    def __delitem__(self, key):
        print('__delitem__',key)
obj = Foo()
result = obj['k1']      # Automatic trigger execution__ getitem__
obj['k2'] = 'jack'      # Automatic trigger execution__ setitem__
del obj['k1']             # Automatic trigger execution__ delitem__

9. iter()

This is the iterator method! The reason why lists, dictionaries and tuples can carry out for loops is that the iter() method is defined inside them. If you want the object of a custom class to be iterated, you need to define this method in the class and make the return value of this method an iteratable object. This iter() method of the class is called when the for loop is used to traverse the object in the code.

Common classes:

class Foo:
    pass
obj = Foo()
for i in obj:
    print(i)
# report errors: TypeError: 'Foo' object is not iterable<br># The reason is that Foo objects are not iteratable
 Add a__iter__(),But nothing is returned:
class Foo:
    def __iter__(self):
        pass
obj = Foo()
for i in obj:
    print(i)
# Error reported: typeerror: iter() returned non iterator of type 'nonetype'
#The reason is__ iter__ Method does not return an iteratable object

Return iteration objects:

class Foo:
    def __init__(self, sq):
        self.sq = sq
    def __iter__(self):
        return iter(self.sq)
obj = Foo([11,22,33,44])
for i in obj:
    print(i)

The best way is to use the generator:

class Foo:
    def __init__(self):
        pass
    def __iter__(self):
        yield 1
        yield 2
        yield 3
obj = Foo()
for i in obj:
    print(i)

10,len()

In Python, if you call the built-in len() function to get the length of an object, in the background, you actually call the len() method of the object. Therefore, the following code is equivalent:

len('ABC')
3
'ABC'.__len__()
3

Python's list, dict, str and other built-in data types implement this method, but your custom class needs to be well designed to implement the len method.

11. repr()

The function of this method is similar to that of str(). The difference is that str() returns the string seen by the user, while repr() returns the string seen by the program developer. In other words, repr() serves debugging. Usually both codes are the same.

class Foo:
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return "this is %s" % self.name
    __repr__ = __str__

12. add__: Addition operation  _ sub_: Subtraction operation  _ mul_: Multiplication operation  _ div_: Division operation  _ mod_: Remainder operation__ pow: power operation

These are arithmetic operation methods. You need to design specific operation code for your class. Some Python built-in data types, such as int, have these methods. Python supports overloading of operators, that is, rewriting.

class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b
   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)

13. author author information

__author__ = "Jack"
def show():
    print(__author__)
show()

14. slots

As a dynamic language, Python can continue to add any number or any type of variables or methods to classes or objects after class definition and instantiation. This is a feature of a dynamic language. For example:

def print_doc(self):
    print("haha")

class Foo:
    pass

obj1 = Foo()
obj2 = Foo()
# Dynamically add instance variables
obj1.name = "jack"
obj2.age = 18
# Dynamically add instance methods to classes
Foo.show = print_doc
obj1.show()
obj2.show()

But! What if I want to limit the variables that an instance can add? You can make slots restrict the variables of the instance. For example, only the instance of Foo is allowed to add the name and age attributes.

def print_doc(self):
    print("haha")
class Foo:
    __slots__ = ("name", "age")
    pass
obj1 = Foo()
obj2 = Foo()
# Dynamically add instance variables
obj1.name = "jack"
obj2.age = 18
obj1.sex = "male"       # This sentence will pop up an error
# However, you cannot restrict the addition of methods to classes
Foo.show = print_doc
obj1.show()
obj2.show()
because'sex'be not in__slots__Cannot bind because it is in the list of sex Property, attempting to bind sex Will get AttributeError Error.
Traceback (most recent call last):
  File "F:/Python/pycharm/201705/1.py", line 14, in <module>
    obj1.sex = "male"
AttributeError: 'Foo' object has no attribute 'sex'

It should be reminded that the attributes defined by slots only work on the instance of the current class, but not on the subclass that inherits it. Think about it. If you inherit a parent class and somehow find that some variables cannot be defined, isn't that a big problem? If necessary, subclasses are also restricted, unless slots are also defined in the subclass. In this way, the allowed attributes of subclass instances are their own slots plus the slots of the parent class.

Member protection and access mechanism

Some objects you don't want to access externally, and you can't access them even by calling class objects. Please finish this chapter carefully.

Private member

class obj:
    def __init__(self,name):
        self.name=name
    def pri(self):
        print self.name
    __age = 18
    # The double underlined variables are private variables, which can only be accessed inside the class, but not outside
a = obj('zhao')
a.pri()

Operation results:

zhao

If you want to call this private member in a class, you can use it.

class obj:
    def __init__(self,name):
        self.name=name
    def prin(self):
        print self.name
    __age = 18
    # The double underlined variables are private variables, which can only be accessed inside the class, but not outside
    @classmethod
    # If you want to call in a class, first call the class method.
    def pri(cls):
        print cls.__age
        # Then in use
a = obj('zhao')
a.prin()
obj.pri()
# In this way, private variables in the class are called directly

Operation results:

zhao
18

Use the get set del method to manipulate private members

class obj:
    def __init__(self,name):
        self.name=name
    def prin(self):
        print self.name
    __age = 18
    # The double underlined variables are private variables, which can only be accessed inside the class, but not outside
    @classmethod
    # If you want to call in a class, first call the class method.
    def pri(cls):
        print cls.__age
        # Then in use
    @classmethod
    def set_age(cls,value):
        cls.__age = value
        return cls.__age
        # This usage is to change__ Value of age
    @classmethod
    def get_age(cls):
        return cls.__age
        # This usage is to return directly__ Value of age
    @classmethod
    def del_age(cls):
        del cls.__age
        # This usage is to delete directly__ Value of age

print obj.get_age()
# This is a direct call out__ Return value of age 18
print obj.set_age(20)
# This is a direct change__ The value of age returns a value of 20
obj.del_age()
# Here is direct deletion__ Value of age

Thinking: since it is a private variable and does not allow external access, why should it be called and changed later? Because private variables can be additionally detected, processed, processed, etc. For example, to judge the value of value, use isinstance and then make an if else judgment.

Using private variables can protect internal variables, which cannot be changed externally, but it can be detected and processed.

Here we extend the protection mechanism of private members, using__ Age is actually - > obj_ obj__ Age is protected. To put it bluntly, you can directly use obj_ obj__ Age can directly call the internal private variable age.

Propety decorator

The way to disguise a class method as a property call is to turn a function in the class into something like a property~
At first, the method of calling the class used parentheses. Now it has become an attribute to read and set storage.
For example:

Common calling methods

class obj:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age
        # Set these to private variables
    def get_age(self):
        return self.__age
    def set_age(self,value):
        if isinstance(value,int):
            self.__age=value
        else:
            raise ValueError('Non integer type')
    def del_age(self):
        print 'delete over'
a = obj('langzi',18)
print a.get_age()
a.set_age(20)
print a.get_age()

Using the decorator

class obj:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age
        # Set these to private variables
    @property
    def age(self):
        return self.__age
    @age.setter
    def age(self,value):
        if isinstance(value,int):
            self.__age=value
        else:
            raise ValueError('Non integer type')
    @age.deleter
    def age(self):
        print 'delete over'
a = obj('langzi',18)
# Using these decorators, you can use the methods of classes and objects to call directly
print a.age
# Here is the value of age returned by the direct call
a.age=20
# Here is to directly use setter to convert the value
print a.age
del a.age
# Delete age

Of course, this calling method is troublesome. Each time, it is to instance classes and objects one by one. There is a more simple and intuitive method.

Use the property() function even more halved

In addition to using decorators to disguise a method as a property, the property() function in Python's built-in builtins module provides us with a second way to set class properties.

class People:

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def get_age(self):
        return self.__age

    def set_age(self, age):
        if isinstance(age, int):
            self.__age = age
        else:
            raise ValueError

    def del_age(self):
        print("Delete age data!")

    # The core is in this sentence
    age = property(get_age, set_age, del_age, "Age")    


obj = People("jack", 18)
print(obj.age)
obj.age = 19
print("obj.age:  ", obj.age)
del obj.ag

Disguise a method as a property through the statement age = property(get_age, set_age, del_age, "age"). The effect is the same as that of the decorator.

Parameters of property() function:

The first parameter is the method name, which is automatically executed when calling the instance. Property
The second parameter is the method name, which is the method automatically executed when the instance. Property = XXX
The third parameter is the method name, which is automatically executed when calling the del instance. Property
The fourth parameter is the string, which calls the instance. Property__ doc__ Description information when.

Topics: Python OOP