Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Python Object-oriented Getting Started tutorial


May 29, 2021 Article blog


Table of contents


Object-oriented programming and functional programming (process-oriented programming) are both methods of programming, but with a slight difference.

Process-oriented programming:

1. 导入各种外部库
2. 设计各种全局变量
3. 写一个函数完成某个功能
4. 写一个函数完成某个功能
5. 写一个函数完成某个功能
6. 写一个函数完成某个功能
7. 写一个函数完成某个功能
8. ......
9. 写一个main函数作为程序入口

In multi-function programs, many important data is placed in the global data area so that they can be accessed by all functions. E ach function can have its own local data, encapsulate some functional code into a function, and then call the function without having to write it repeatedly. From the organization of the code is based on the business logic from top to bottom code.

Object-oriented programming:

1. 导入各种外部库
2. 设计各种全局变量
3. 决定你要的类
4. 给每个类提供完整的一组操作
5. 明确地使用继承来表现不同类之间的共同点
6. 根据需要,决定是否写一个main函数作为程序入口

In object-oriented programming, functions and variables are further encapsulated as classes, which are the basic elements of a program that bind data and operations together and protect data from accidental changes by outside functions. Examples of classes and classes (also known as objects) are the core object-oriented concepts and are fundamentally different from process-oriented and functional programming.

It's not about object-oriented programming, it depends on how easy your program is designed, but for now, it's basically object-oriented programming.

The basic usage of the class

Object-oriented is defined by defining class classes, so object-oriented programming is to use only class classes, encapsulate in class classes, inherit functionality, and construct parameters to pass in for easy control.

Case one

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

class studetn:
# 定义一个类名为studetn
def __init__(self,idx):
# 定义初始化构造,这里使用init,还有别的属性比如reversed,iter之类的
self.idx=idx
# 初始化变量,方便继承
def runx(self):
# 定义运行函数,从上面继承变量
print self.idx
# 打印出idx的值,或者做一些别的处理
time.sleep(1)
a=studetn('a')
a.runx()
# 这是类的调用,一定要记得类的使用方法,首先传入参数,类赋值给一个变量a
# 然后调用这个类下面定义的函数

Some terminology concepts, since there is an object-oriented programming this tall definition, naturally to match some tall concepts.

Class: A collection of objects that have the same properties and methods. I t defines the properties and methods common to each object in the collection. The object is called an instance of the class.

2, example: also known as an object. By the initialization method defined by the class, the specific value is given to become a "flesh and blood entity".

3, instantiation: the process or operation of creating an instance of a class.

4, instance variables: defined in the instance of the variable, only on the current instance.

5. Class variables: Class variables are variables that are common to all instances. Class variables are defined in the class, but outside the method body.

6, data members: class variables, instance variables, methods, class methods, static methods and properties, such as the general name.

7. Method: A function defined in a class.

8, static method: do not need instantiation can be executed by the class method

9, class method: class method is the method of operating the class itself as an object.

10, method override: If the method inherited from the parent class does not meet the needs of the child class, the method of the parent class can be rewritten, this process is also known as override.

11, encapsulation: the internal implementation of wrapped up, external transparency, to provide api interface call mechanism

12. Inheritance: That is, a derived class inherits the variables and methods of the base class.

13, polymorphism: according to the different types of objects in different ways to deal with.

Classes and instances

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

class cc:
ccc = 'ccc'
# cc就是类名 如果想要继承别的类 就class cc(threading) 意思就是从threading继承
def __init__(self,a,b,c):
self.a=a
self.b=b
self.c=c
# 定义构造的过程就是实例化
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()
# 这两个就是调用类里面的方法
print e.c
#实例变量指的是实例本身拥有的变量。每个实例的变量在内存中都不一样。
print e.ccc
#类变量,在类里面找到定义的变量。

Call the three methods of the class

The instance method

# -*- coding: utf-8 -*-
# @Time : 2018/5/3 0003 17:16
# @Author : Langzi
# @Blog : www.langzi.fun
# @File : 面向对象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()
# 这种调用方法就是实例方法

Static method

Static methods are called by classes and have no default parameters. R emove the self from the instance method parameters, and then add @staticmethod above the method definition to become a static method. I t belongs to a class, regardless of the instance. I t is recommended to use only class names. H ow static methods are called. ( Although instance names can also be used.) static method way called)

# -*- coding: utf-8 -*-
# @Time : 2018/5/3 0003 17:21
# @Author : Langzi
# @Blog : www.langzi.fun
# @File : 面向对象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()
#这里就直接调用了类的变量,只在类中运行而不在实例中运行的方法

There are often features that are related to classes but require static methods when running without the need for instances and class participation. S tatic methods such as changing environment variables or modifying the properties of other classes can be used. This situation can be solved directly with functions, but it also diffuses the code inside the class, making maintenance difficult.

Class method

The class method is called by the class, decorated with @classmethod, and passes in at least one cls (referring to the class itself, similar to self) argument. W hen you execute a class method, the class that calls the method is automatically assigned to cls. I t is recommended to use only class names. H ow the class method is called. ( Although instance names can also be used.) how class methods are called)

The actual case

If you want to construct a class, accept a web site and the status code for that site, and then print it out. It's 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 the use of the instance method, although it can be implemented, but sometimes the incoming parameters are not ('langzi', 200) such a format, but ('langzi-200'), so what? The first step is to split this, but it's cumbersome to implement with an instance method, and you can use a class method at this point.

# -*- coding: utf-8 -*-
# @Time : 2018/5/3 0003 17:27
# @Author : Langzi
# @Blog : www.langzi.fun
# @File : 面向对象5.py
# @Software: PyCharm
import sys
import requests
reload(sys)
sys.setdefaultencoding('utf-8')
class gg:
url = 0
stat = 0
# 因为使用classmethod后会传入新的变量,所以一开始是需要自己先定义类变量
def __init__(self,url=0,stat=0):
# 这里按照正常的定义构造函数
self.url=url
self.stat=stat
@classmethod
# 装饰器,立马执行下面的函数
def split(cls,info):
# 这个函数接受两个参数,默认的cls就是这个类的init函数,info就是外面传入进来的
url,stat=map(str,info.split('-'))
# 这里转换成了格式化的结构
data = cls(url,stat)
# 然后执行这个类第一个方法,这个类构造函数需要传入两个参数,于是就传入了两个参数
return data
# 这里就直接返回了函数结果
def outer(self):
print self.url
print self.stat

r = gg.split(('langzi-200'))
r.outer()
# 这里是调用类方法,与调用实例方法一样

The characteristics of the class

encapsulation

Encapsulation is the implementation code that places data and specific operations inside an object and is not accessible externally. The method of the class must be called before it can start.

Case

class cc:
ccc = 'ccc'
# cc就是类名 如果想要继承别的类 就class cc(threading) 意思就是从threading继承
def __init__(self,a,b,c):
self.a=a
self.b=b
self.c=c
print e.ccc
#类变量,在类里面找到定义的变量。
print ccc
# 这里会报错,这就是封装。类中的函数同理。

inherit

When we define a class, we can inherit from an existing class, the new class is called subclass, and the inherited class is called the base class, parent class, or superclass (Base class, Super class). For example, we've written a class called Animal, and there's a run() method that prints directly:

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

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

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

What are the benefits of inheritance? T he biggest benefit is that the child class gets the full functionality of the parent class. Because Animial implements the run() method, Dog and Cat, as its subclasses, automatically own the run method when nothing is done:

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

When both the child class and the parent class have the same run() method, we say that the run of the child class overrides the run of the parent class and always calls the run() of the child class when the code is running. In this way, we get another benefit of inheritance: polymorphism.

Polymorphism

To understand the benefits of polymorphism, we also need to write another function that accepts a Animal-type variable:

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

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

run_twice(Animal())
运行结果:
Animal is running...
Animal is running...

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

run_twice(Dog())
运行结果:
Dog is running...
Dog is running...

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

run_twice(Cat())
运行结果:
Cat is running...
Cat is running...

It doesn't look interesting, but think about it, and now, if we define another Tortoise type, it's derived from Animal:

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

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

run_twice(Tortoise())
运行结果:
Tortoise is running slowly...
Tortoise is running slowly...

You'll find that the addition of a subclass of Animal doesn't have to make any modifications to the run_twice(), in fact, any function or method that relies on Animal as an argument can work without modification because of polymorphism.

The benefit of polymorphism is that when we need to pass in Dog, Cat, Tortoise... W e just need to receive the Animal type, because Dog, Cat, Tortoise... I t's all Animal types, and then you can follow the Animal type. Because the Animal type has a run() method, any type passed in, as long as it is an Animal class or subclass, automatically calls 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 exactly its subtype, and the run() method of the specific call is on the Animal, Dog, Cat, or Tortoise object, determined by the exact type of the object at runtime, which is the true power of polymorphism: the caller only calls, regardless of the details, and when we add a subclass of Animal, just make sure that the run() M ethod is written correctly, regardless of how the original code was called. This is the famous "open and close" principle:

  • Open to extensions: Allow new Animal subclasses;
  • Closed for modifications: You do not need to modify functions such as run_twice() that depend on the Animal type.

Summary: Inheritance can take all the functions of the parent class directly, so that there is no need to start with zero, subclasses only need to add their own unique methods, can also be the parent class is not suitable for the method override overriding; W hen calling a class instance method, try to treat the variable as a parent class type so that all child class types can be received normally; Any time there is no suitable class to inherit, it is inherited from the object class.

Magic method

There's a reference above to the iter, reverse method in addition to the __init__, and here's a closer look at what else there are besides init initialization.

__init__ :      构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__div__: 除运算
__mod__: 求余运算
__pow__: 幂

Specific use

1. __doc__

Explanatory documentation and information. Python is self-built and does not require customization.

class Foo:
""" 描述类信息,可被自动收集 """
def func(self):
pass
# 打印类的说明文档
print(Foo.__doc__)

2. __init__()

The instantiation method automatically triggers execution when an instance is created from a class.

class Foo:
def __init__(self, name):
self.name = name
self.age = 18
obj = Foo('jack') # 自动执行类中的 __init__ 方法

3. __module__ and __class__

Module indicates which module the object of the current operation belongs to. C lass indicates which class the object of the current operation belongs to. Both are also Python built-in and do not require customization.

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

Result: main

4. __del__()

A destruct method that is automatically triggered when an object is released in memory.

Note: This method generally does not need to be customized because Python comes with a memory allocation and release mechanism unless you need to specify some action at the time of release. Calls to destructors are automatically triggered by the interpreter when garbage collection occurs.

class Foo:
def __del__(self):
print("我被回收了!")

obj = Foo()
del obj

5. __call__()

If you write the method for a class, you can call it by bracketing the instance of the class.

Note: The execution of the construction method is performed in parentheses of the class, i.e., the object is the class name (), and for the call() method, it is triggered by the object's parenthesis, i.e. the object () or class () ()

class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__

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

callable(Student())

Results:

True

6. __dict__

List all members of a class or object! A very important and useful property, Python is self-built and does not require users to define it themselves.

class Province:
country = 'China'
def __init__(self, name, count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print'func'
# 获取类的成员
print(Province.__dict__)
# 获取 对象obj1 的成员
obj1 = Province('HeBei',10000)
print(obj1.__dict__)
# 获取 对象obj2 的成员
obj2 = Province('HeNan', 3888)
print(obj2.__dict__)

7. __str__()

If a str() method is defined in a class, the return value of the method is output by default when the object is printed. T his is also a very important approach that requires the user to define it himself.

The following class, without defining the str() method, prints the result: < main. Foo object at 0x000000000210A358>

class Foo:
pass
obj = Foo()
print(obj)
定义了__str__()方法后,打印结果是:'jack'
class Foo:
def __str__(self):
return 'jack'
obj = Foo()
print(obj)

8、__getitem__()、__setitem__()、__delitem__()

Take values, assign values, and remove this "three swordsman" approach, which we've seen many times in Python, such as the front @property decorator.

In Python, identifiers are followed by parentheses, which usually represent the meaning of executing or calling methods. T he brackets are added after the identifier, which usually means value. P ython designed three special members, getitem(), setitem(), and delitem(), to perform actions related to parentheses. They represent values, assignments, and deletion of data, respectively.

Here's what to do:

a = 标识符[] :  执行__getitem__方法
标识符[] = a :  执行__setitem__方法
del 标识符[] :  执行__delitem__方法

If a class defines all three magic methods at the same time, the instance of the class behaves like a dictionary, as 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'] # 自动触发执行 __getitem__
obj['k2'] = 'jack' # 自动触发执行 __setitem__
del obj['k1'] # 自动触发执行 __delitem__

9. __iter__()

This is the iterator approach! L ists, dictionaries, and tuples can be looped because they define the iter() method internally. I f the user wants the object of a custom class to be iterative, they need to define the method in the class and make the return value of the method an iterative object. This iter() method of the class is called when the object is traversed in code using the for loop.

Normal class:

class Foo:
pass
obj = Foo()
for i in obj:
print(i)
# 报错:TypeError: 'Foo' object is not iterable<br># 原因是Foo对象不可迭代
添加一个__iter__(),但什么都不返回:
class Foo:
def __iter__(self):
pass
obj = Foo()
for i in obj:
print(i)
# 报错:TypeError: iter() returned non-iterator of type 'NoneType'
#原因是 __iter__方法没有返回一个可迭代的对象

Returns one iteration object after another:

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 to do this 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 try to get the length of an object, in the background, you actually call the object's len() method, so the following code is equivalent:

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

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

11. __repr__()

This method works much like str(), the difference being that str() returns the string that the user sees, and repr() returns the string that the program developer sees, that is, repr() is for debugging. Usually the code is the same.

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

12. __add__: Add operation __sub__: subtract operation __mul__: multiply operation __div__: except operation __mod__: find the remaining operation __pow__: power operation

These are arithmetic methods that require you to design your own specific operation code for the class. S ome Python built-in data types, such as int, come with these methods. Python supports overloading of operators, which is overrides.

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__

Python is a dynamic language that continues to add random numbers or any type of variable or method to a class or object after it has been defined and instantiated, which is a feature of dynamic languages. For example:

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

class Foo:
pass

obj1 = Foo()
obj2 = Foo()
# 动态添加实例变量
obj1.name = "jack"
obj2.age = 18
# 动态的给类添加实例方法
Foo.show = print_doc
obj1.show()
obj2.show()

But! W hat if I want to limit the variables that an instance can add? You can make slots limit the variables of an instance, for example, only instances of Foo are allowed to add name and age properties.

def print_doc(self):
print("haha")
class Foo:
__slots__ = ("name", "age")
pass
obj1 = Foo()
obj2 = Foo()
# 动态添加实例变量
obj1.name = "jack"
obj2.age = 18
obj1.sex = "male" # 这一句会弹出错误
# 但是无法限制给类添加方法
Foo.show = print_doc
obj1.show()
obj2.show()
由于'sex'不在__slots__的列表中,所以不能绑定sex属性,试图绑定sex将得到AttributeError的错误。
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 is important to note that the properties defined by slots only work on instances of the current class and not on the subclasses that inherited it. T hink about it, too, and if you inherit a parent class and somehow find that some variables can't be defined, isn't that a big deal? If non-essential subclasses are also restricted, unless slots are also defined in child classes, the properties that child class instances are allowed to define are their own slots plus slots of the parent class.

Member protection and access mechanisms

Some objects you do not want external access to, even by calling class objects can not be accessed, then please carefully complete this chapter.

Private members

class obj:
def __init__(self,name):
self.name=name
def pri(self):
print self.name
__age = 18
# 加上双下划线的就是私有变量,只能在类的内部访问,外部无法访问
a = obj('zhao')
a.pri()

Results:

zhao

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

class obj:
def __init__(self,name):
self.name=name
def prin(self):
print self.name
__age = 18
# 加上双下划线的就是私有变量,只能在类的内部访问,外部无法访问
@classmethod
# 如果要在类中调用,首先调用类方法
def pri(cls):
print cls.__age
# 然后在使用
a = obj('zhao')
a.prin()
obj.pri()
# 通过这样直接调用类中的私有变量

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
# 加上双下划线的就是私有变量,只能在类的内部访问,外部无法访问
@classmethod
# 如果要在类中调用,首先调用类方法
def pri(cls):
print cls.__age
# 然后在使用
@classmethod
def set_age(cls,value):
cls.__age = value
return cls.__age
# 这个用法就是改变__age的值
@classmethod
def get_age(cls):
return cls.__age
# 这个用法就是直接返回__age的值
@classmethod
def del_age(cls):
del cls.__age
# 这个用法就是直接删除__age的值

print obj.get_age()
# 这里是直接调用出__age的值 返回值18
print obj.set_age(20)
# 这里是直接改变__age的值 返回值20
obj.del_age()
# 这里是直接删除__age的值

Think: Since it is a private variable that is not accessible externally, why should it be called and changed later? B ecause private variables can be additionally detected, processed, processed, and so on. For example, to determine the value of value, use isinstance and then make if-else judgment.

Private variables can be used to protect internal variables, which cannot be changed externally, but can be detected.

Here is the introduction of the protection mechanism of private members, the use of __age to protect the private variable is actually - >obj._obj__age look like, to put it bluntly, you can directly use the obj._obj__age you can directly call the internal private variable age.

Propety decorator

The way to disguise the method of a class as a property call is to turn a function inside the class into a property-like thing - the method that initially calls the class uses parentheses, and now it becomes a property for reading settings storage. For example:

A commonly used calling method

class obj:
def __init__(self,name,age):
self.__name=name
self.__age=age
# 讲这些设置成私有变量
def get_age(self):
return self.__age
def set_age(self,value):
if isinstance(value,int):
self.__age=value
else:
raise ValueError('非整数类型')
def del_age(self):
print 'delete over'
a = obj('langzi',18)
print a.get_age()
a.set_age(20)
print a.get_age()

Use a decorator

class obj:
def __init__(self,name,age):
self.__name=name
self.__age=age
# 把这些设置成私有变量
@property
def age(self):
return self.__age
@age.setter
def age(self,value):
if isinstance(value,int):
self.__age=value
else:
raise ValueError('非整数类型')
@age.deleter
def age(self):
print 'delete over'
a = obj('langzi',18)
# 使用这些装饰器,可以使用类与对象的方法直接调用
print a.age
# 这里就是直接调用返回age的值
a.age=20
# 这里就是直接使用setter把值转换
print a.age
del a.age
# 删除age

Of course, this kind of call method is a bit of a hassle, each time is a de-instance class and object, there is a simpler and more intuitive method.

Use the property() function in half more

In addition to masquerading a method as a property using a decorator, the property() function in Python's built-in buildins module gives us 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("删除年龄数据!")

# 核心在这句
age = property(get_age, set_age, del_age, "年龄")

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

A method is disguised as a property by statement age-property (get_age, set_age, del_age, "age"). The effect is the same as that of the decorator.

The argument to the property() function:

第一个参数是方法名,调用 实例.属性 时自动执行的方法
第二个参数是方法名,调用 实例.属性 = XXX时自动执行的方法
第三个参数是方法名,调用 del实例.属性 时自动执行的方法
第四个参数是字符串,调用 实例.属性.__doc__时的描述信息。
Reprinted from: http://www.langzi.fun/Python object-oriented programming .html

That's all you'll find out about Python's Object-Oriented Getting Started tutorial