[Python basics] decorators, iterators, generators

Decorator

The decorator is essentially a Python function , which allows other functions to add additional functions without any code changes . The return value of the decorator is also a function object.
It is often used in scenarios with aspect requirements, such as insertion Scenarios such as logging, performance testing, transaction processing, caching, and permission verification. Decorator is an excellent design to solve this kind of problem. With decorator, we can extract a lot of code that has nothing to do with the function itself and continue to reuse it.

1. Function call

#定义一个函数
def hi(mes="我要玩亚索"):
    return "中路是我的,"+mes


print(hi())
# 拷贝函数
greet = hi
print(greet())

try:
	# 删除原函数
    del hi
    print(hi())
except Exception as e:
    print("函数已被删除")
finally:
    print(greet())

2. Call function in function

def hi(name="锐雯"):
    print("now you are inside the hi() function")

    def greet():
        return "now you are inside the greet() function"

    def welcone():
        return "now you are inside the welcome() function"

    print(greet())
    print(welcone())
    print("now you are back in the hi() function")


hi()

try:
	# 在主函数中调用hi函数中的greet函数
    greet()
except Exception as e:
    print("函数不存在")

3. Function call returns function call

def hi(name="锐雯"):
    def greet():
        return "now you are inside the greet() function"

    def welcome():
        return "now you are inside the welcome() function"

    if name=="锐雯":
        return greet
    else:
        return welcome


a = hi()
print(a)
print(a())
a = hi("亚索")
print(a())

4. Function parameter passing-passing in function parameter

def hi():
    return "It's a nice day"


def doSomethingToSee(func):
    print(func())
    print("I should do something")


doSomethingToSee(hi)

5. The function passes in the function parameter and returns the function call

def a_new_decorator(a_func):
    def wrapTheFunction():
        print("在函数调用前我正在做一些无聊的事情")
        a_func()
        print("终于结束函数调用了,我都快累死了")

    return wrapTheFunction


def a_function_requiring_decoration():
    print("我是一个需要装饰的函数")


a_function_requiring_decoration()
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
a_function_requiring_decoration()

The above function a_new_decorator is a decorator.
Now python allows decorator calls to use @syntax sugar

Let's use @syntax sugar to reconstruct the above decorator:

import functools


def a_new_decorator(a_func):
    def wrapTheFunction():
        print("在函数调用前我正在做一些无聊的事情")
        a_func()
        print("终于结束函数调用了,我都快累死了")

    return wrapTheFunction


@a_new_decorator
def a_function_requiring_decoration():
    print("我是一个需要装饰的函数")


print(a_function_requiring_decoration.__name__)
a_function_requiring_decoration()

The above syntactic sugar "@a_new_decorator" is equivalent to "a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)" before reconstruction.

note:

We find that "a_function_requiring_decoration._ name_ " returns wrapTheFunction, which means that the original function's name, function comments, and documentation have been modified to functions in the decorator closure

To prevent this from happening

We import a module

import functools/from functools import wraps

import functools


def a_new_decorator(a_func):
	@functools.wraps(a_func)
    def wrapTheFunction():
        print("在函数调用前我正在做一些无聊的事情")
        a_func()
        print("终于结束函数调用了,我都快累死了")

    return wrapTheFunction


@a_new_decorator
def a_function_requiring_decoration():
    print("我是一个需要装饰的函数")


print(a_function_requiring_decoration.__name__)
a_function_requiring_decoration()

Can solve this problem

You can also use the following two methods:

  1. Use decorator.py file
    decorator.py is a very simple decorator enhancement package. You can define the wrapper function intuitively first, and then use the decorate(func, wrapper) method to complete a decorator.
    The decorator implemented by decorator.py can completely retain the name of the original function. The
    only problem with doc and args is that the source code of the decorator returned by inspect.getsource(func) needs to be changed to inspect.getsource(func._ wrapped_ )

import decorator

import decorator
import datetime
# 装饰器的优化


def wrapper(func, *args, **kwargs):
    print("我正在装扮自己")
    return func(*args, **kwargs)


def logging(func):
    # 用wrapper装饰func
    return decorator.decorate(func, wrapper)


# @logging
def hi():
    print("my name is Q")


a= logging(hi)
a()

  1. Use wrapt files

import wrapt

Wrapt is a package with very complete functions. It is used to implement various decorators.
Decorators implemented with wrapt do not need to worry about all the problems encountered in inspect before, because it handles them for you, even inspect.getsource(func). Accurate

import wrapt

@wrapt.decorator
def logging(wrapped, instance, *args, **kwargs):
    print("我是个装饰器的外套")
    return wrapped(*args, **kwargs)

@logging
def sayHi(*args, **kwargs):
    print("Hi")

sayHi()

Decorator with parameters

1. Decorator based on function implementation

Put a layer of decorator outside the decorator, specifically used to pass parameters to the decorator

import functools

def add_2_somenumber(num, add_num=1):
    print("---1---")
    def know_whatToDo(func):
        print("---2---")
        @functools.wraps(func)
        def wirte_function_name(*arg, **kwargs):
            print("---3---")
            print(func.__name__, " was called at here")
            print("as a result, the answer is %d" % (num + add_num))
            return func(*arg, **kwargs)
        return wirte_function_name
    return know_whatToDo

@add_2_somenumber(2,3)
def print_result():
    print("开始活动了")
    print("---4---")


print_result()
2. Decorator based on class implementation

The decorator function is actually such an interface constraint.
It must accept a callable object as a parameter, and then return a callable object
. Generally callable objects in Python are functions,
but there are exceptions, as long as an object overloads the __call__() method , then This object is callable

In the class object:

_ init_ : used to pass parameters
_ call_ : used to build decorators

# 装饰类
import functools


class logit(object):
    def __int__(self, logfile="out.log"):
        self.login_file = logfile

    def __call__(self, func):
        @functools.wraps(func)
        def wrapped_function(*arg, **kwarg):
            login_string = func.__name__+" was called "
            print(login_string)
            return func(*arg, **kwarg)
        return wrapped_function


@logit(logfile="out.log")
def myfunc_test():
    print("这是类装饰器的产生")


myfunc_test()
1. The decorator principle:
      1) The original function cannot be modified.
      2) The calling method cannot be modified.
2. The decorator is implemented through nested functions and closures.
3. The decorator execution order: the onion rule.
4. The decorator is modified by syntactic sugar "@".
5. Remember the principle that the decorator returns a reference to the closure function referenced by the decorated function

Commonly used decorators

There are three decorators for properties: setter, getter, and deleter, all of which are encapsulated on the basis of property().
Because setter and deleter are the second and third parameters of property(), you cannot directly apply @ syntax

class Classmate:
    def __init__(self):
        self.age = 15

    @property
    def set_name(self, value):
        self.name = value

student = Classmate()
student.name="Q"
print(student.age)
print(student.name)

With the understanding of @property decorator, the principles of these two decorators are similar.
@staticmethod returns a staticmethod class object.
@classmethod returns a classmethod class object.
They all call their own __init__() construction. function

Iterator

from collections.abc import Iterable
from collections.abc import Iterator

content = list()
content = [x*x for x in range(10)]
print(type(content))
It can be found that common lists, dictionaries, collections, ancestors, and strings are all iteration objects
print(isinstance([], Iterable))
print(isinstance((), Iterable))
print(isinstance({
    
    }, Iterable))
print(isinstance("", Iterable))

Iterated objects can be traversed by for

for i in content:
    print(i, end=" ")
print()
Can a class be an iterable object?
class ClassMate(object):
    def __init__(self):
        self.names = []

    def add_name(self, name):
        self.names.append(name)


student = ClassMate()
student.add_name("老王")
student.add_name("小张")
student.add_name("小李")
print(isinstance(student, Iterable))

Found that the ordinary class is not an iterable object.
Only when the __iter__ method appears in the class object, the class becomes an iterable object.

class ClassMate(object):
    def __init__(self):
        self.names = []

    def add_name(self, name):
        self.names.append(name)

    def __iter__(self):
        pass


student = ClassMate()
student.add_name("老王")
student.add_name("小张")
student.add_name("小李")
# 当类对象中出现__iter__方法时,该类就变成了可迭代对象
print(isinstance(student, Iterable))

# 我们使用for循环遍历,发现还是不能够迭代类对象
# 这时候我们就可以使用类中的一个方法__next__,使其迭代对象
try:
    for i in student:
        print(i)
except Exception as e:
    print("不能够进行迭代")

1. Call the iteration of the original own class through an iterable class

class ClassMate(object):
    def __init__(self):
        self.names = []
        self.index = 0

    def add_name(self, name):
        self.names.append(name)

    def __iter__(self):
        # 返回一个可以迭代的对象
        return ClassRoom(self)

    def __next__(self):
        if self.index+1 <= len(self.names):
            result = self.names[self.index]
            self.index += 1
            return result
        else:
            # 如果没有这句话,对象将会一直返回None
            # 这里报错StopIteration,并停止迭代
            raise StopIteration


class ClassRoom(object):
    def __init__(self, obj):
        self.index = 0
        self.obj = obj

    def __iter__(self):
        pass

    def __next__(self):
        if self.index + 1 <= len(self.obj.names):
            result = self.obj.names[self.index]
            self.index += 1
            return result
        else:
            # 如果没有这句话,对象将会一直返回None
            # 这里报错StopIteration,并停止迭代
            raise StopIteration


student = ClassMate()
student.add_name("老王")
student.add_name("小张")
student.add_name("小李")
for i in student:
    print(i)

2. Iterate yourself

class ClassMate(object):
    def __init__(self):
        self.names = []
        self.index = 0

    def add_name(self, name):
        self.names.append(name)

    def __iter__(self):
        # 返回一个可以迭代的对象
        return self

    def __next__(self):
        if self.index+1 <= len(self.names):
            result = self.names[self.index]
            self.index += 1
            return result
        else:
            # 如果没有这句话,对象将会一直返回None
            # 这里报错StopIteration,并停止迭代
            raise StopIteration


student = ClassMate()
student.add_name("老王")
student.add_name("小张")
student.add_name("小李")
for i in student:
    print(i)

Builder

A generator is a special iterator.
Ordinary generators
only need to change the brackets when generating the iterator to parentheses.

def get_test1(num):
    print(num)
    i = 0
    print(i, end=" ")
    while i < num:
        print(i, end=" ")
        ret = yield i
        i += 1


n = get_test1(10)
for i in range(10):
    next(n)


def get_test2(num):
    print(num)
    i = 0
    print(i, end=" ")
    while i < num:
        print(i, end=" ")
        ret = yield i
        print(ret)
        i += 1


n1 = get_test2(10)
next(n1)
n1.send("hahahaha")
next(n1)

When the yield appears when the function is called, it becomes a generator. The
generator can get data through _ next_

obj.send(msg) When the program is in progress, the yield call has a return value, which is the msg transmitted by send

Note: When the send method is called, the next method must be called first to start iterative generation

When the sub-function runs to yield, the program will first return the value to a function call, and then stop waiting until the next time the data in the generator is obtained.

Guess you like

Origin blog.csdn.net/hide_in_darkness/article/details/109229767