The article directories

  • The iterator
    • concept
  • The generator
    • concept
    • Yield of grammar
    • use
  • decorator
    • Decorator pattern
    • Python decorator
    • define
    • application



yieldThe [ji ː ld] the [ji ː ld]

To produce a crop; Produce (a profit, benefit, etc); Provide; The yield; Concessions; Give up; To pay out

N. production; Output; profits

The sign above means “let”

The iterator

concept


What is an iterator? For those of you who have studied C/C++, it is used in the STL to access a particular container and to iterate over elements in the STL container.

Iterator provides some basic operators: *, + + = = |! +, =, etc. These operations are basically the same as C/C++ pointer interfaces for array elements, except that the iterator has the ability to traverse complex data structures, known as smart Pointers.

Like for lists and tuplesfor... inWhen iterating, Python actually iterates over lists and tuples, not lists and tuples themselves:

In Python, iterators also have the ability to iterate over user-defined classes. Iterator objects need to support both __iter__() and next() methods, with the former returning the iterator itself and the latter returning the next element.

Examples of iterating custom classes:

class example(object) :
    def __init__(self,num) :
        self.num=num
    def __iter__(self) :
        return self
    def __next__(self) :
        if self.num <= 0:
            raise StopIteration
        tmp = self.num
        self.num -= 1
        return tmp
    
a = example(3)
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
Copy the code

The class Example is an iterated object, executed each timenext()The self.num attribute is checked when the operation is performed, and an exception is thrown to indicate the end of the iteration if <=0.

The generator

concept


When class linear traversal operations can be implemented through the iterator __iter()__ and __next__() methods, but not flexible and convenient, for example, there is no attribute variable for the function to store the state, that is, linear traversal of the function is not supported.

So what’s the solution? Python3.X supports linear traversal using the yield generator’s methods. The yield statement is used only to define a generator function and can occur only within a generator function, returning a generator when the generator function is called.

What is a generator? The concept of generators comes from programs that work together. Take the consumer and producer model for example, where the Python generator is the producer’s role (data provider), and each time the generator program waits, once the consumer/user calls the next() method, the generation proceeds to the next step, The Node of the currently encountered internal data is then placed in a public buffer visible to the next consumer user, and the consumer/user waits for the Node to be retrieved from the buffer.

For example, implementing an incremental generator:

def add() :
    num = 0
    while True:
        yield num
        num += 1

a = add()
print(next(a))
print(next(a))
print(next(a))
Copy the code

Defining generator functionsadd(), only when the user callsnext()Method when only internal data will beNodeInstead of getting stuck in an infinite loop, offer and wait.



See from theyieldThe function of an expression can be divided into two parts:

  1. Return data num
  2. Entering the wait_AND_GET state means that the program pauses at this location and is activated when the consumer calls the ‘next() method again.

Iterators vs. generators: Both iterators use the next() method to fetch data, but iterators use their own implementation of the next() method to progressively return data, while generators use yield to automatically supply data and make the program wait for further user action. Generators are more flexible and convenient.

Yield of grammar


In Python3.X, yield becomes an expression, not a statement. But it must be placed inside a function. If written as a statement, an error will be reported (the return value is actually thrown away), for example:

yield n
x=yield n
Copy the code

Since yield is an expression, it can be combined with other expressions, for example:

x=y+z*(yield 2)
a=b+c+yield d
Copy the code

Next () method

When the user callsnext()Method executed toyieldExpression, returns n, and then the program enterswaitStatus only when next executednext()Method to resume from this point and continue executing the following code, all the way to the nextyieldExpression. If there’s no next oneyieldThe code is thrownStopIterationThe exception.

Send (MSG

Perform asend(msg)Will resume the generator’s run and then send the valuemsgWill become the currentyieldThe return value of an expression. When the program resumes, it continues to execute the following code, again to the next oneyieldCode to throw if there is no next oneStopIterationThe exception.

When usingsend(msg)When a message is sent to the generator, wait_and_GET detects the new type and wakes up the generator while the method getsmsgAnd copy it to X, as shown below:



The above functions are equivalent to:

def test() :
    print('Remember the triple link.')
    put(1)
    x = wait_and_get()
    print('x=', x)
    put(2)
    y = wait_and_get()
    print('y=', y)
    print('There's no yield, Stop will be thrown.')
Copy the code

When the first call to the next() method is executed at the first wait_and_get, the generator enters wait and prints’ Remember to triple ‘and’ 1 ‘; Send (666) is called to start the generator at the first wait_and_get and assign the parameter 666 to the variable X. Execution continues at the second wait_AND_GET and the generator enters wait again. Send (888) is then called, and the generator starts at the second wait_and_GET and assigns 888 to variable Y. Since there is no yield expression left, the generator raises StopIteration.

In particular, the first call is either usednext(), or usesend(None), cannot be usedsend()To send a non-None value because non-None is sentwait_and_get. The program didn’t stop at the beginningwait_and_getIn code, only use firstnext()orsend(None)Method will stop afterwait_and_getAt this time can be usedsendSend a non-None value.



Throw ()

Generator providesthrow()Method to control the execution of the generator by throwing exceptions from within the generator.



GeneratorExitGives the generator a chance to perform some exit cleanup.

Close the generator

The generator provides oneclose()Method to turn off the generator. When usingclose()Method, the generator exits directly from the current state and is used againnext()Will get the StopIteration exception.



In fact,close()And the way to do that is bythrow()Method to sendGenerationExitException to shut down the generator, which is equivalent to the following code:

def close(self) :
    try:
        self.throw(GeneratorExit)
    except(GeneratorExit,StopIteration):
        pass
    else:
        raise RuntimeError("generator ignored GeneratorExit")
Copy the code

Address of the blogger CSDN: wzlodq.blog.csdn.net/

use


Generators save more memory than lists and tuples. The generator generates one data item at a time until it is empty, which can be looping through in a for loop with less memory. But you need to remember the current state in order to return to the next data item. A generator is an object with a next() method, and a sequence type holds all data items, accessed by index.

For example, finding leap years:



Linear traversal generator can transform nonlinear speech processing into linear way, a typical example is binary tree access. The traditional approach is to use recursion:

def deal_tree(node) :
    if not node:
        return
    if node.leftnode:
        deal_tree(node.leftnode)
    process(node)
    if node.rightnode:
        deal_tree(node.rightnode)
Copy the code

The recursive approach of processing each node requires the process() method to be placed in the access process, which is error-prone and unclear. A better way is to first convert the tree node access to linear, with a generator implementation:

def deal_tree(node) :
    if not node:
        return
    if node.leftnode:
        for i in walk_tree(node.leftnode):
            yield i
    yield node
    if node.rightnode:
        for i in walk_tree(node.rightnode):
            yield i
Copy the code

decorator

Decorator pattern


A modifier is a function that extends the functionality of an original function, special in that the return value is a function.

The concept of decorators comes from the design pattern, also known as the Decorator pattern. Specific details can be seen in the design pattern series blog, for example, for example, the game hero’s combat ability can be improved by upgrading equipment, adding skills, using items, etc. When it is realized, it is naturally impossible to create every combination of situations for call. Modifiers work: Use the modifiers used to upgrade equipment; Use item modifiers when using items. The goal is to change the state of objects dynamically at run time rather than compile time, and to expand the program by adding and removing decorators in a composite manner rather than modifying the original code to meet business needs.

The Decorator pattern is specific to the Java language, and in order to add and subtract decorators in a flexible way, the Java language requires a more complex structure of class objects. Python implements the ability to add or subtract decorators by composition at the syntactic level.

Python decorator


Python supports flexible invocation of the Decorator pattern syntactically in two ways:

@A
def f() :
Copy the code

Equivalent to adding A modifier A to function f, Python will handle it as f = A(f). Modifiers can be added without restriction and can be used at multiple levels:

@A
@B
@C
def f() :
Copy the code

Python will process f=A(B(C(f))).

Decorators with arguments have the following syntax:

@A(args)
def f() :
Copy the code

Python first executes A(args) to get A decorator() function that says:

def f() :. _deco = A(args) f = _deco(f)Copy the code

define


Each Decorator has a corresponding function, and subsequent functions are processed by either returning the original function object ora new one. Note in particular that decorators can only be used to handle functions and class methods.

Func: func: func: func: func: func: func: func: func: func: func

def A(func) :
	# processing func
	return func
	
@A
def f(args) :pass
Copy the code

Return a new function object. Note that neew_func is defined in the same form as the function to be processed (optionally with an undefined parameter). The syntax is as follows:

def A(func) :
	def new_func(*args,**argkw) :
		Do some extra work
		return func(*args,**argkw) # call the original function to continue processing
	return new_func
	
@A
def f(args) :pass
Copy the code

The above code defines the new function in A, which then returns the new function. A new function can do something before calling the original function. If you want to do something after calling the function, you can do it by calling the return value of the function:

def A(args) :
	def new_func(*args,**argkw) :
		# Some pre-call processing
		result = func(*args,**argkw)
		if result:
			# Work after further calls
			return new_result
		else:
			return result
	return new_func

@A
def f(args) :pass
Copy the code

Since the decorator() function is called with arguments, a new decorator() function is returned, consistent with the first form.

def A(arg) :
	def _A(func) :
		def new_func(args) :
			Get some work done
			return func(args)
		return new_func
	return _A

@A(arg)
def f(args) :pass
Copy the code

application


Using decorators increases the flexibility of your program, reduces coupling, and is suitable for user login checking, log processing, and so on. This approach of combining functions with each other is more of a building block, allowing the function to be further decomposed into a simple enough function, and then strung together flexibly through the mechanism of the Decorator.

Application example: a multi-user program will have a lot of functions and permissions related, the traditional method is to establish the rights role class, and then each user inherits the rights role, but this method is not only prone to error, and management, modify is also very troublesome. Use a Decorator to handle user permission logic by calling a Decorator () function. Define permission management classes:

class Permission:
    # Ordinary users
    def userPermission(self,function) :
        def new_func(*args,**kwargs) :
            obj = args[0]
            if obj.user.hasUserPermission(): # Check whether you have the corresponding permission
                ret = function(*args,**kwargs)
            else:
                ret = 'No User Permission'
            return ret
        return new_func
    # administrator
    def adminPermission(self,function) :
        def new_func(*args,**kwargs) :
            obj = args[0]
            if obj.user.hasAdminpermission(): # Check whether you have the corresponding permission
                ret = function(*args,**kwargs)
            else:
                ret ='No Admin Permission'
            return ret
        return new_func
Copy the code

Then to deal with the actual business code, just add the actual permission restrictions decorators for the desired functionality:

class Action:
    def __init__(self,name) :
        self.user = UserService.newUser(name)
    @Permission.userPermission User permission is required
    def listAllpoints(self) :
        return 'do real list all points'
    @Permission.adminPermission Administrator permission is required
    def setup(self) :
        return 'do real setup'
Copy the code

Finally, the business method is called:

if __name__ == "main":
    action = Action('user')
    print(action.listAllpoints())# Execute real business code
    print(action.setup)
Copy the code

Decorators have great advantages over traditional approaches in that they can separate the trivial work of checking user permissions from the business invocation code, and they can easily be decorated with inspection functions on top of the business logic code. The Python blog series continues to be updated

Original is not easy, please do not reprint (this is not rich visitors to add to the problem) blogger homepage: wzlodq.blog.csdn.net/ wechat public number: weow lo dong qiang if the article is helpful to you, remember a key three connect ❤