Python examples of adorners and iterators and generators

Source: Internet
Author: User
Tags define function iterable python decorator
Here's a little piece to bring you a cliché about Python's adorners, iterators, and generators. Small series feel very good, now share to everyone, also for everyone to make a reference. Let's take a look at it with a little knitting.

In learning Python, the three "name device" for those who have no other language programming experience, should be considered a small difficulty, this blog on the blogger himself on the adorner, iterator and generator understanding to explain.

Why use adorners

What is an adorner? "Decoration" from the literal meaning of who is a particular building in accordance with a certain way of thinking and style to beautify a behavior, the so-called "device" is a tool, for Python, the adorner is able to add new features without modifying the original code, such as a software on-line, We need to be able to add new features without modifying the source code and not modifying the way it is called, and in Python it can be implemented with adorners, as well as the subsequent extensibility when writing code, and let's take a step-by-step look at the python decorator.

A simple example of the introduction of a non-parametric adorner

First look at a few simple lines of code, the code runs the result is to sleep 2 seconds, and then print "Hello boy!" :


Import timedef foo (): "" "Print" "" Time.sleep (2) print ("Hello boy!") Foo ()

We now need to add a program timing feature for it, but we cannot modify the original code:


Import Timedef Timmer (func): Def wrapper (): "" "  Chronograph Function" ""  Time_start=time.time ()  func ()  time_end= Time.time ()  print ("Run time is%f"% (Time_end-time_start)) return wrapperdef foo (): "" "Print" "" Time.sleep (2) print (" Hello boy! ") Foo=timmer (foo) foo () #运行结果Hello boy! Run Time is 2.000446

See! We did this without modifying the original code, because the function is also an object, so we can pass the function foo as a parameter to the function Timmer.

In Python, there is a cleaner way to replace Foo=timmer (foo), which is called the syntactic sugar in Python, using @timmer.


Import Timedef Timmer (func): Def wrapper (): "" "  Chronograph Function" ""  Time_start=time.time ()  func ()  time_end= Time.time ()  print ("Run time is%f"% (Time_end-time_start)) return Wrapper@timmer  #等于 Foo=timmer (foo) def foo () : "" "Print" "" "Time.sleep (2) print (" Hello boy! ") Foo ()

Let's take a step-by-step analysis of the execution of the function:

1. Import the time module


Import time

2. Define function Timmer, define function does not execute code inside function


def Timmer (func):

3. Call adorner, equivalent to Foo=timer (foo), is the function foo as a parameter to wear the function Timmer


@timmer

4. Run the function Timmer, accept the parameter Func=foo


def Timmer (func):

5. Within the function Timmer, the function is defined wrapper,wrapper the internal code of the function is not executed, and the function wrapper is returned as the return value


Return wrapper

6. Assign the return value to Foo, and in the 3rd step, Foo=timmer (foo), remember


@timmer #等于 Foo=timmer (foo)

7. Run the function foo (), but here the function is not the original function, you can print Foo, right, because we passed wrapper as the return value to Foo, so the execution of Foo here is the execution of wrapper, In order to be sure of this you can also print wrapper, whose memory addresses are the same, so they all point to the same address space:


<function timmer.<locals>.wrapper at 0x00000180e0a8a950> #打印foo的结果 <function timmer.<locals>. Wrapper at 0x000001f10ad8a950> #打印wrapper的结果foo ()

8. Run function wrapper, record start time, execute function func, at 4th step, Func is assigned by Foo, run Func is run the original function foo, sleep 2 seconds, print the string;


Time_start=time.time () time.sleep (2) print ("Hello boy!")

9. Record end time, print run time, program end.


Hello boy! Run Time is 2.000161

With reference decorator

In the previous example, the original function has no parameters, the following is a when the original function has parameters, how to modify the adorner function?


Import Timedef Timmer (func): Def wrapper (*args,**kwargs): "" "  Chronograph Function" ""  start_time=time.time ()  res=func (* Args,**kwargs)  end_time=time.time ()  print ("Run time is%f"% (end_time-start_time))  return res return Wrapper@timmer def my_max (x, y): "" "returns the maximum value of two values" "" Res=x if x > y else y time.sleep (2) return Resres=my_max () print (res) #运行结果Run Time is 2.000175

When the original function has the need to pass in parameters, in this example My_max has two positions to be passed into the parameter, only need to add two parameters on wrapper, this example uses the variable parameter (*args,**kwargs) is also possible, this is @timmer equals My_max (=timmer) (My_max)

Let's take a look at an adorner with parameters:


def auth (filetype): Def auth2 (func):  def wrapper (*args,**kwargs):   if filetype = = "File":    username=input (" Please input your username: ")    passwd=input (" Please input your password: ")    if passwd = = ' 123456 ' and username = = ' F Rank ':     print ("Login successful")     func ()    else:     print ("Login error!")   if filetype = = ' sql ':    print ("No sql")  return wrapper return Auth2@auth (filetype= ' file ') #先先返回一个auth2 = = "@ Auth2 = = "Index=auth2 (index) = =" Index=wrapperdef index (): Print ("Welcome to China") index ()

If the adorner itself has parameters, it requires more than one layer of inline functions, the next step we analyze the execution process:

1. Defining function Auth


def auth (filetype):

2. Call the interpreter, first run the function auth (filetype= ' file ')


@auth (filetype= ' file ')

3. Run function auth, define a function auth2, and return as a return value, then this @auth (filetype= ' file ') is equivalent to @auth2, equivalent to Index=auth2 (index)


def auth (filetype): Def auth2 (func):  def wrapper (*args,**kwargs):  return wrapper return auth2

4.auth2 (index) executes, func=index, defines the function wrapper, and returns, when index is actually equal to wrapper.


def wrapper (*args,**kwargs): Return wrapper

5. When running index, run wrapper, run the function internal code, filetype== "file", prompt the user to output the user name and password, determine whether the input is correct, if correct, then execute function func (), equal to perform the original index, print


if filetype = = "File":    username=input ("Please input your username:")    passwd=input ("Please input your password:"    if passwd = = ' 123456 ' and username = = ' Frank ':     print ("Login successful")     func ()

6. Run the results test


Please input your username:frankplease input your password:123456login successfulwelcome

Adorners can also be superimposed:


Import Time#def Timmer (func): Def wrapper (): "" "  Chronograph Function" ""  Time_start=time.time ()  func ()  time_end= Time.time ()  print ("Run time is%f"% (Time_end-time_start))  # print ("---", wrapper) return Wrapperdef Auth ( filetype): Def auth2 (func):  def wrapper (*args,**kwargs):   if filetype = = "File":    username=input ("please Input your username: ")    passwd=input (" Please input your password: ")    if passwd = = ' 123456 ' and username = = ' Frank ':     Print ("Login successful")     func ()    else:     print ("Login error!")   if filetype = = ' sql ':    print ("No sql")  return wrapper return Auth2@timmer@auth (filetype= ' file ') #先先返回一个auth2 = = "@auth2 = =" index=auth2 () = = "Index=wrapperdef index (): Print (" Welcome to China ") index () #测试结果Please input your username: Frankplease input your password:123456login successfulwelcome to Chinarun time is 7.966267

Annotation optimization


Import Timedef Timmer (func): Def wrapper (): "" "  Calculation program Run Time" ""  Start_time=time.time ()  func ()  end_time= Time.time ()  print ("Run Time is%s:"% (end_time-start_time)) return Wrapper@timmerdef My_index (): "" "Print Welcome" "" Time.sleep (1) print ("Welcome to china!") My_index () print (my_index.__doc__) #运行结果Welcome to china! Run time is 1.0005640983581543: Calculating program run times

When we use the adorner, although the code itself is not modified, but at run time, such as the above example, run My_index actually running wrapper, if we print my_index annotation information, will print wrapper () of the comment information, So how do you optimize it?

You can import wraps in the module Functools, as shown in the following:


Import timefrom functools Import wrapsdef Timmer (func): @wraps (func) def wrapper (): "" "  Calculation program Run Time" ""  start_time= Time.time ()  func ()  end_time=time.time ()  print ("Run Time is%s:"% (end_time-start_time)) return Wrapper@timmerdef My_index (): "" "Print Welcome" "" Time.sleep (1) print ("Welcome to china!") My_index () print (my_index.__doc__) #运行结果Welcome to china! Run time is 1.0003223419189453: print Welcome

Thus, on the surface, the original function has not changed.

Why use iterators

Literally, iteration is the activity of repeating the feedback process, the purpose is usually to compare the desired goals or results, in Python can be implemented with an iterator, first to describe the advantages and disadvantages of the iterator, if you do not understand can skip, and so read this blog look back, I believe you will understand the meaning:

Advantages:

Iterators are not indexed when they are evaluated, so they can traverse objects that are not indexed, such as dictionaries and files

Iterators are lazy calculations and more memory-efficient than lists

Disadvantages:

Unable to get the length of the iterator, no list is flexible

You can only take the value back and not the value backwards.

What is an iterator

So what in Python is an iterator?

As long as the object has __iter__ (), then it is iterative, and the iterator can use the function next () to take the value

Let's look at a simple iterator:


My_list=[1,2,3]li=iter (my_list)  #li =my_list.__iter__ () print (LI) print (Next (LI)) print (next) print (Li )) #运行结果 <list_iterator object at 0x000002591652c470>2

As you can see, using the built-in function ITER can convert the list to a list iterator, use next () to get the value, take a value once, take the value out, and then use the next () to report an abnormal stopiteration, which can be avoided by exception handling, Try-except-else is one of the most common exception handling structures:


My_list=[1,2,3]li=iter (my_list) while true:try:  print (Next (LI)) except stopiteration:  print ("Over")  Break Else:  print ("get!") #运行结果get!get!get! Over

Viewing the object and iterator objects that can be iterated

You can use the Iterable module to determine whether an object is iterative:


From collections import iterables= "Hello" #定义字符串l =[1,2,3,4] #定义列表t = (All-in-all) #定义元组d ={' a ': 1} #定义字典set1 ={1,2,3,4} #定义集合f = Open ("A.txt") #定义文本 # to see if all are iterations of print (Isinstance (s,iterable)) print (Isinstance (l,iterable)) print (Isinstance (t, iterable)) Print (Isinstance (d,iterable)) print (Isinstance (set1,iterable)) print (Isinstance (f,iterable)) # Run result Truetruetruetruetruetrue

By judging, it can be determined that the commonly used data types we know can be iterated.

Use the iterator module to determine whether an object is an iterator:


From collections import iterable,iterators= "Hello" l=[1,2,3,4]t= (d={' a ': 1}set1={1,2,3,4}f=open ("A.txt") # Check to see if the print (Isinstance (s,iterator)) print (Isinstance (l,iterator)) print (Isinstance (t,iterator)) print ( Isinstance (D,iterator)) print (Isinstance (set1,iterator)) print (Isinstance (f,iterator)) # Run result Falsefalsefalsefalsefalsetrue

It is known that only the file is an iterator, so you can directly use next () instead of converting to an iterator.

What is a generator

A producer is a function with yield.

Let's look at a simple generator


Def my_yield (): Print (' first ') yield 1g=my_yield () print (g) #运行结果 <generator object My_yield at 0x0000024366d7e258>

The generator is also an iterator


From collections Import Iteratordef My_yield (): Print (' first ') yield 1g=my_yield () print (Isinstance (g,iterator)) # Run result True

Then you can use next () to take a value.


Print (Next (g)) #运行结果first1

The execution process of the generator

Let's take a look at the following example to understand the process of production execution


Def my_yield (): Print (' first ') yield 1 print (' second ') yield 2 print (' third ') yield 3g=my_yield () next (g) next (g) next (g) # Run result Firstsecondthird

1. Define the generator My_yield and assign it to the G


Def My_yield (): G=my_yield ()

2. Start the first execution of next (), start executing the production function, print the first statement, pause when encountering Yileld, and return a 1, if you want to print the return value, this will show 1


Print (' first ') yield 1

3. Execute 2 more times to print the string (pauses once for each execution)


Print (' second ') yield 2 print (' third ') yield 3

4. If you add another next (), the stopiteration will be reported as abnormal.

Each time the generator is paused, the state of the function is saved, as shown in the following example:


def foo (): I=0 while True:  yield i  i+=1g=foo () for NUM in G:if num <:  print (num) Else:  break# Run result

The For loop implies next (), every next time, pauses once, the IF statement is judged once, and then executes next next, you can see that our while loop does not have an infinite loop, but the state is preserved.

Co-process function

Let's take a look at the following generator and execution results


Def eater (name): Print ('%s start to eat food '%name) and True:  food=yield  print ('%s get%s, to start eat '% (name,f OOD)) print (' Done ') e=eater (' Frank ') Next (e) e.send (' egg ') #给yield送一个值, and continue executing code e.send (' tomato ') #运行结果Frank start to eat Foodfrank get egg, to start eatfrank get tomato, to start eat

Send can be directly transmitted to yield, which contains the function of yield expression we also called the function of the co-process,

When you run the program, you cannot send directly, you must first use the next () Initial generator.

If there are more than one such function, then we have to go to next each time we execute, in order to prevent forgetting this step, we can use the adorner initialization:


Def init (func): Def wrapper (*args):  res = func (*args)  Next (res)  # Execute next  return res return here Wrapper@initdef Eater (name): Print ('%s start to eat food '%name) and True:  food=yield  print ('%s get%s, to start Eat '% (Name,food)) print (' Done ') e=eater (' Frank ') e.send (' egg ') e.send (' tomato ')

So when there are more generators in the program that need to be initialized, call this adorner directly.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.