Python object-oriented advanced and applied

Python object-oriented advanced and applied

overview

  • Inheritance【Supplementary】
  • Built-in functions [supplement]
  • exception handling
  • reflection

1. Inheritance 【Supplement】

  • Significance of inheritance: extracting public methods into the parent class is beneficial to increase code reusability.

  • The way inheritance is written:

# 单继承
class Base(object):
    pass


class Foo(Base):
    pass
# 多继承
class Base(object):
    pass

class Bar(object):
    pass

class Foo(Base,Bar):
    pass

When calling members in a class, follow:

  • First look for it in your own class, if not, go to the parent class to find it.
  • If the class has multiple inheritance (multiple parent classes), first look for the left and then the right.

1.1 mro and c3 algorithm

If there is an inheritance relationship in the class, you can mro()get the inheritance relationship of the current class (the order of finding members)

Example 1:

mro(A) = [A] + [B,C]
mro(A) = [A,B,C]
mro(A) = [A] + merge( mro(B), mro(C), [B,C] )
mro(A) = [A] + merge( [object], [object], [] )
mro(A) = [A] + [B,C,object]
mro(A) = [A,B,C,object]
mro(A) = [A] + merge( mro(B), mro(C), [B,C] )
mro(A) = [A] + merge( [], [C], [,C] 
mro(A) = [A] + [B,C]
class C(object):
    pass


class B(object):
    pass


class A(B, C):
    pass


print(A.mro())  # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]
print(A.__mro__)  # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
print(B.mro())  #class C(object):
    pass


class B(object):
    pass


class A(B, C):
    pass


print(A.mro())  # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]
print(A.__mro__)  # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
print(B.mro())  #[<class '__main__.B'>, <class 'object'>]

Example 2:

mro(A) = [A] + merge( mro(B), mro(C), [B,C] )
mro(A) = [A] + merge( [], [D], [] )
mro(A) = [A] + [B,C,D]
mro(A) = [A,B,C,D]
class D(object):
    pass


class C(D):
    pass


class B(object):
    pass


class A(B, C):
    pass


print( A.mro() ) # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]

Example 3:

mro(A) = [A] + merge( mro(B),mro(C),[B,C])
mro(A) = [A] + merge( [], [C], [C])
mro(A) = [A,B,D,C]
class D(object):
    pass


class C(object):
    pass


class B(D):
    pass


class A(B, C):
    pass


print(A.mro()) # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class 'object'>]

Example 4:

mro(A) = [A] + merge( mro(B), mro(C), [B,C])

mro(A) = [A] + merge( [B,D], [C,D], [B,C])

mro(A) = [A] + [B,C,D] 
mro(A) = [A,B,C,D] 
class D(object):
    pass


class C(D):
    pass


class B(D):
    pass


class A(B, C):
    pass


print(A.mro()) # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]

Example 5:

简写为:A -> B -> D -> G -> H -> K -> C -> E -> F -> M -> N -> P -> object
mro(A) = [A] + merge( mro(B),          mro(C),      mro(P),      [B,C,P])
                  []   [N]     [P]          [P]

mro(A) = [A,B,D,G,H,K,C,E,F,M,N,P]

-----------------------------------------------------
mro(B) = [B] + merge( mro(D), mro(E), [D,E])

mro(D) = [D] + merge(mro(G),mro(H), [G,H])

mro(G) = [G]

mro(H) = [H,K]

mro(B) = [B] + merge( [], [E,M], [E])
mro(B) = [B,D,G,H,K,E,M]


-----------------------------------------------------
mro(C) = [C] + merge(mro(E),mro(F),[E,F])

mro(E) = [E,M]

mro(F) = [F,M,N] 

mro(C) = [C] + merge([M],[M,N] ,[])
mro(C) = [C,E,F,M,N]
class M:
    pass


class N:
    pass


class E(M):
    pass


class G:
    pass


class K:
    pass


class H(K):
    pass


class D(G, H):
    pass


class F(M, N):
    pass


class P:
    pass


class C(E, F):
    pass


class B(D, E):
    pass


class A(B, C, P):
    pass


print(A.mro()) # 简写为:A -> B -> D -> G -> H -> K -> C -> E -> F -> M -> N -> P -> object

Special supplement: one sentence to get the inheritance relationship

Inheritance: From left to right, depth first, big and small diamonds, keep the top , based on this sentence, you can find the inheritance relationship faster.

1.2 The difference between py2 and py3 (understand)

Overview:

  • Before python2.2, only classic classes are supported [from left to right, depth first, big and small diamonds, no top]

  • Later, Python wanted classes to inherit object by default (object-oriented objects in other languages ​​basically inherit object by default). At this time, it was found that the original classic class could not directly integrate this function, and there was a bug.

  • Therefore, Python decided not to modify the original classic class, but to create a new class to support this function. [From left to right, depth first, big and small diamonds, keep the top.

    • Classic class, does not inherit the object type

      class Foo:
          pass
      
    • New-style classes, directly or indirectly inherit from object

      class Base(object):
          pass
      
      class Foo(Base):
          pass
      
  • In this way, after python2.2, classic classes and new-style classes coexist. (officially supported is 2.3)

  • Eventually, the classic classes were discarded in python3 and only the new-style classes were kept.

Summary: The difference between Python2 and Python3 regarding object-oriented.

  • Py2:

    • A classic class that does not inherit the object type. [From left to right, depth first, big and small diamonds, no top]

      class Foo:
          pass
      
    • New-style class, directly obtains and indirectly inherits the object type. [From left to right, depth first, big and small diamonds, keep the top – C3 algorithm]

      class Foo(object):
          pass
      

      or

      class Base(object):
          pass
      
      class Foo(Base):
          pass
      
  • Py3

    • New-style classes, discarding the classic classes and only keeping the new-style classes. [From left to right, depth first, big and small diamonds, keep the top – C3 algorithm]

      class Foo:
          pass
      
      class Bar(object):
          pass
      

2. Addition of built-in functions

  • classmethod、staticmethod、property 。

  • callable, whether it can be executed after adding parentheses.

    • function

      def func():
          pass
      
      print( callable(func) )#True
      
    • kind

      class Foo(object):
          pass
      
      print( callable(Foo) )# True
      
    • __call__objects with methods in the class

      class Foo(onject):
          pass
      
      obj = Foo()
      print( callable(obj) )#True
      
      class Foo(object):
      
          def __call__(self, *args, **kwargs):
              pass
      
      
      obj = Foo()
      print(callable(obj)) #True
      

    So when you see the following situation in the future, you must first think that handler can be: function, class, object with call method, what exactly is it, you need to analyze it according to the calling relationship of the code.

    def do_something(handler):
        handler()
    
    • super, find members upwards according to the mro inheritance relationship.

      class Base(object):
      
          def message(self, num):
              print("Base.message", num)
              super().message(1000)
      
      
      class Bar(object):
      
          def message(self, num):
              print("Bar.message", num)
      
      
      class Foo(Base, Bar):
          pass
      
      
      obj = Foo()
      obj.message(1)
      
      >>> Base.message 1
      >>> Bar.message 1000
      
    • type, get the type of an object.

    v1 = "达莱"
    result = type(v1)
    print(result)  # <class 'str'>
    
    v2 = "达莱"
    print(type(v2) == str)  # True
    
    v3 = [11, 22, 33]  # list(...)
    print(type(v3) == list)  # True
    
    class Foo(object):
        pass
    
    v4 = Foo()
    
    print( type(v4) == Foo )  # True
    
  • isinstance, to determine whether the object is an instance of a class or its subclasses.

    class Top(object):
        pass
    
    
    class Base(Top):
        pass
    
    
    class Foo(Base):
        pass
    
    
    v1 = Foo()
    
    print( isinstance(v1, Foo) )   # True,对象v1是Foo类的实例
    print( isinstance(v1, Base) )  # True,对象v1的Base子类的实例。
    print( isinstance(v1, Top) )   # True,对象v1的Top子类的实例。
    
    class Animal(object):
        def run(self):
            pass
    
    class Dog(Animal):
        pass
    
    class Cat(Animal):
        pass
    
    data_list = [
        "达莱",
        Dog(),
        Cat(),
    	"root"
    ]
    
    for item in data_list:
        if type(item) == Cat:
            item.run()
        elif type(item) == Dog:
            item.run()
        else:
            pass
        
    for item in data_list:
        if isinstance(item, Animal):
            item.run()
        else:
            pass
    
  • issubclass, to determine whether a class is a descendant of a class.

    class Top(object):
        pass
    
    
    class Base(Top):
        pass
    
    
    class Foo(Base):
        pass
    
    
    print(issubclass(Foo, Base))  # True
    print(issubclass(Foo, Top))  # True
    

3. Exception handling

If you encounter some errors during program development 不可预知or you are too lazy to make some judgments, you can choose to use exception handling.

try:
    res = requests.get(url=url)
except Exception as e:
    代码块,上述代码出异常待执行。
print("结束")
import requests

while True:
    url = input("请输入要下载网页地址:")
    
    try:
        res = requests.get(url=url)
    except Exception as e:
        print("请求失败,原因:{}".format(str(e)))
        continue
        
    with open('content.txt', mode='wb') as f:
        f.write(res.content)
num1 = input("请输入数字:")
num2 = input("请输入数字:")
try:
    num1 = int(num1)
    num2 = int(num2)
    result = num1 + num2
    print(result)
except Exception as e:
    print("输入错误")

Common application scenarios in the future:

  • Call WeChat API to realize WeChat message push, WeChat payment, etc.
  • Alipay payment, video playback, etc.
  • Database or redis connection and operation
  • Calling the function of the third-party video player, the error is caused by the problem of the third-party program.

The basic format of exception handling:

try:
    # 逻辑代码
except Exception as e:
    # try中的代码如果有异常,则此代码块中的代码会执行。
try:
    # 逻辑代码
except Exception as e:
    # try中的代码如果有异常,则此代码块中的代码会执行。
finally:
    # try中的代码无论是否报错,finally中的代码都会执行,一般用于释放资源。

print("end")

"""
try:
    file_object = open("xxx.log")
    # ....
except Exception as e:
    # 异常处理
finally:
    file_object.close()  # try中没异常,最后执行finally关闭文件;try有异常,执行except中的逻辑,最后再执行finally关闭文件。
"""    

3.1 Abnormal Segmentation

import requests

while True:
    url = input("请输入要下载网页地址:")
    
    try:
        res = requests.get(url=url)
    except Exception as e:
        print("请求失败,原因:{}".format(str(e)))
        continue
        
    with open('content.txt', mode='wb') as f:
        f.write(res.content)

If you want to perform more detailed exception handling on exceptions, as follows:

import requests
from requests import exceptions

while True:
    url = input("请输入要下载网页地址:")
    try:
        res = requests.get(url=url)
        print(res)    
    except exceptions.MissingSchema as e:
        print("URL架构不存在")
    except exceptions.InvalidSchema as e:
        print("URL架构错误")
    except exceptions.InvalidURL as e:
        print("URL地址格式错误")
    except exceptions.ConnectionError as e:
        print("网络连接错误")
    except Exception as e:
        print("代码出现错误", e)
        
# 提示:如果想要写的简单一点,其实只写一个Exception捕获错误就可以了。

If you want to subdivide the processing of errors, for example: the occurrence of Key errors and the occurrence of Value errors are handled separately.

Basic format:

try:
    # 逻辑代码
    pass

except KeyError as e:
    # 小兵,只捕获try代码中发现了键不存在的异常,例如:去字典 info_dict["n1"] 中获取数据时,键不存在。
    print("KeyError")

except ValueError as e:
    # 小兵,只捕获try代码中发现了值相关错误,例如:把字符串转整型 int("无诶器")
    print("ValueError")

except Exception as e:
    # 王者,处理上面except捕获不了的错误(可以捕获所有的错误)。
    print("Exception")

There are many subdivided errors built into Python for you to choose from.

常见异常:
"""
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问n x[5]
KeyError 试图访问字典里不存在的键 inf['xx']
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
"""
更多异常:
"""
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
"""

3.2 Custom Exceptions & Throwing Exceptions

The custom exception is as follows:

class MyException(Exception):
    pass
try:
    pass
except MyException as e:
    print("MyException异常被触发了", e)
except Exception as e:
    print("Exception", e)

The above code defines catching MyException in except, but it will never be triggered. Because the default exceptions have specific trigger conditions, for example: the index does not exist, the key does not exist will trigger IndexError and KeyError exceptions.

For our custom exceptions, if you want to trigger, you need to use: raise MyException()class implementation.

class MyException(Exception):
    pass


try:
    # 。。。
    raise MyException()
    # 。。。
except MyException as e:
    print("MyException异常被触发了", e)
except Exception as e:
    print("Exception", e)
class MyException(Exception):
    def __init__(self, msg, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.msg = msg


try:
    raise MyException("xxx失败了")
except MyException as e:
    print("MyException异常被触发了", e.msg)
except Exception as e:
    print("Exception", e)
class MyException(Exception):
    title = "请求错误"


try:
    raise MyException()
except MyException as e:
    print("MyException异常被触发了", e.title)
except Exception as e:
    print("Exception", e)

Case 1 : You and I cooperate in collaborative development, and you call the method I wrote.

  • I define a function

    class EmailValidError(Exception):
        title = "邮箱格式错误"
    
    class ContentRequiredError(Exception):
        title = "文本不能为空错误"
        
    def send_email(email,content):
        if not re.match("\[email protected]",email):
            raise EmailValidError()
    	if len(content) == 0 :
            raise ContentRequiredError()
    	# 发送邮件代码...
        # ...
    
  • you call the function I wrote

    def execute():
        # 其他代码
        # ...
        
    	try:
            send_email(...)
        except EmailValidError as e:
            pass
        except ContentRequiredError as e:
            pass
        except Exception as e:
            print("发送失败")
    
    execute()
    
    # 提示:如果想要写的简单一点,其实只写一个Exception捕获错误就可以了。
    

Case 2 : It has been defined within the framework, and any errors encountered will trigger different exceptions.

import requests
from requests import exceptions

while True:
    url = input("请输入要下载网页地址:")
    try:
        res = requests.get(url=url)
        print(res)    
    except exceptions.MissingSchema as e:
        print("URL架构不存在")
    except exceptions.InvalidSchema as e:
        print("URL架构错误")
    except exceptions.InvalidURL as e:
        print("URL地址格式错误")
    except exceptions.ConnectionError as e:
        print("网络连接错误")
    except Exception as e:
        print("代码出现错误", e)
        
# 提示:如果想要写的简单一点,其实只写一个Exception捕获错误就可以了。

Case 3 : Trigger the specified exception according to the regulations, and each exception has a special meaning.

3.4 Special finally

try:
    # 逻辑代码
except Exception as e:
    # try中的代码如果有异常,则此代码块中的代码会执行。
finally:
    # try中的代码无论是否报错,finally中的代码都会执行,一般用于释放资源。

print("end")

When defining exception handling code in a function or method, pay special attention to finally and return.

def func():
    try:
        return 123
    except Exception as e:
        pass
    finally:
        print(666)
        
func()

Even if return is defined in try or except, the code in the last finally block will be executed.

4. Reflection

Reflection provides a more flexible way for you to operate members in objects ( 对象operate members in the form of strings).

class Person(object):

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

    def show(self):
        message = "姓名{},微信:{}".format(self.name, self.wx)
        return message


user_object = Person("达莱", "da666")

# 对象.成员 的格式去获取数据
print(user_object.name)
print(user_object.wx)
print(user_object.show())

# 对象.成员 的格式无设置数据
user_object.name = "查苏娜"
class Person(object):

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

    def show(self):
        message = "姓名{},微信:{}".format(self.name, self.wx)


user = Person("达莱", "da666")

# getattr 获取成员
getattr(user, "name")  # user.name
getattr(user, "wx")  # user.wx

method = getattr(user, "show")  # user.show
method()
# 或
getattr(user, "show")()

# setattr 设置成员
setattr(user, "name", "查苏娜")  # user.name = "查苏娜"

Four built-in functions are provided in Python to support reflection:

  • getattr, to get members in the object
v1 = getattr(对象,"成员名称")
v2 = getattr(对象,"成员名称", 不存在时的默认值)
  • setattr, to set members in the object
setattr(对象,"成员名称",)
  • hasattr, whether the object contains members
v1 = hasattr(对象,"成员名称") # True/False
  • delattr, delete a member in an object
delattr(对象,"成员名称")

In the future, if you encounter the writing method of object.member again, you can implement it based on reflection.

case:

class Account(object):

    def login(self):
        pass

    def register(self):
        pass

    def index(self):
        pass

    
def run(self):
    name = input("请输入要执行的方法名称:") # index register login xx run ..
    
    account_object = Account()
    method = getattr(account_object, name,None) # index = getattr(account_object,"index")
    
    if not method:
        print("输入错误")
        return 
    method()

4.1 Some Objects

There is such a sentence in Python: 一切皆对象. Each object has its own maintenance members.

  • object is object
class Person(object):
    
    def __init__(self,name,wx):
        self.name = name
        self.wx = wx
	
    def show(self):
        message = "姓名{},微信:{}".format(self.name,self.wx)
        
        
user_object = Person("达莱","da666")
user_object.name
  • classes are objects
class Person(object):
    title = "达莱"

Person.title
# Person类也是一个对象(平时不这么称呼)
  • modules are objects
import re

re.match
# re模块也是一个对象(平时不这么称呼)。

Since reflection supports operating members in objects in the form of strings [equivalent to object.members], members in classes and modules can also be operated on based on reflection.

Simple and rude: as long as you see xx.oo, you can use reflection to achieve it.

class Person(object):
    title = "达莱"

v1 = Person.title
print(v1)
v2 = getattr(Person,"title")
print(v2)
import re

v1 = re.match("\w+","dfjksdufjksd")
print(v1)

func = getattr(re,"match")
v2 = func("\w+","dfjksdufjksd")
print(v2)

4.2 import_module + reflection

If you want to import a module in Python, you can import it through the import syntax; in fact, you can also import it in the form of a string.

Example one:

# 导入模块
import random

v1 = random.randint(1,100)
# 导入模块
from importlib import import_module

m = import_module("random")

v1 = m.randint(1,100)

Example two:

# 导入模块exceptions
from requests import exceptions as m
# 导入模块exceptions
from importlib import import_module
m = import_module("requests.exceptions")

Example three:

# 导入模块exceptions,获取exceptions中的InvalidURL类。
from requests.exceptions import InvalidURL
# 错误方式
from importlib import import_module
m = import_module("requests.exceptions.InvalidURL") # 报错,import_module只能导入到模块级别。
# 导入模块
from importlib import import_module
m = import_module("requests.exceptions")
# 去模块中获取类
cls = m.InvalidURL

In the source code of many projects, there will be import_moduleand getattrto cooperate to import modules and obtain members in the form of strings, for example:

from importlib import import_module

path = "openpyxl.utils.exceptions.InvalidFileException"

module_path,class_name = path.rsplit(".",maxsplit=1) 
# "openpyxl.utils.exceptions"   "InvalidFileException"

module_object = import_module(module_path)

cls = getattr(module_object,class_name)

print(cls)

We can also develop based on this in development to improve the scalability of the code, for example: Please implement a function of sending SMS and WeChat in the project.

Summarize

  1. Understand the mro and c3 algorithms

  2. The difference between python2 and python3 in object-oriented.

  3. built-in function

    staticmethod,classmethod,property,callable,type,isinstance,issubclass,super
    getattr,setattr,hasattr,delattr
    
  4. exception handling

  5. Import modules as stringsimport_module

  6. Manipulate members in the form of strings反射-getattr,setattr,hasattr,delattr

Guess you like

Origin blog.csdn.net/qq_37049812/article/details/119721184