Heim > Backend-Entwicklung > Python-Tutorial > Detaillierte Erläuterung von Beispielen für Dekoratoren, Iteratoren und Generatoren in Python

Detaillierte Erläuterung von Beispielen für Dekoratoren, Iteratoren und Generatoren in Python

黄舟
Freigeben: 2017-07-26 15:45:02
Original
928 Leute haben es durchsucht

Der folgende Editor bringt Ihnen einen alltäglichen Artikel über Dekoratoren, Iteratoren und Generatoren in Python. Der Herausgeber findet es ziemlich gut, deshalb werde ich es jetzt mit Ihnen teilen und es allen als Referenz geben. Folgen wir dem Herausgeber und werfen wir einen Blick darauf

Beim Erlernen von Python sollten die drei „berühmten Tools“ als kleine Schwierigkeit für Leute angesehen werden, die keine Erfahrung im Programmieren in anderen Sprachen haben. In diesem Blog geht es um den Blogger selbst. Dekorateure , Iteratoren und Generatorverständnis werden erklärt.

Warum Dekorateure verwenden

Was sind Dekorateure? „Dekoration“ bedeutet wörtlich das Verschönern eines bestimmten Gebäudes gemäß einer bestimmten Idee und einem bestimmten Stil. Das sogenannte „Gerät“ ist ein Werkzeug, das verwendet werden kann, ohne den ursprünglichen Code zu ändern Nachdem eine Software beispielsweise online ist, müssen wir regelmäßig neue Funktionen hinzufügen, ohne den Quellcode oder die Art und Weise zu ändern, wie sie aufgerufen wird. In Python können wir dies auch beim Schreiben von Code erreichen. Wir müssen auch die spätere Skalierbarkeit berücksichtigen. Schauen wir uns die Dekoratoren Schritt für Schritt an.

Ein einfaches Beispiel stellt einen Parameterlosen Dekorator vor

Sehen wir uns zunächst ein paar einfache Codezeilen an 2 Sekunden lang gedrückt halten und dann „Hallo Junge!“ ausgeben:


import time
def foo():
 """打印"""
 time.sleep(2)
 print("Hello boy!")
foo()
Nach dem Login kopieren

Wir müssen jetzt eine Programm-Timing-Funktion hinzufügen, aber der Originalcode kann nicht sein geändert:


import time
def timmer(func):
 def wrapper():
  """计时功能"""
  time_start=time.time()
  func()
  time_end=time.time()
  print("Run time is %f "%(time_end-time_start))
 return wrapper
def foo():
 """打印"""
 time.sleep(2)
 print("Hello boy!")
foo=timmer(foo)
foo()
#运行结果
Hello boy!
Run time is 2.000446
Nach dem Login kopieren

Schau! Wir haben diese Funktion implementiert, ohne den ursprünglichen Code zu ändern. Da Funktionen auch Objekte sind, können wir die Funktion foo als Parameter an den Funktionstimmer übergeben.

In Python gibt es eine prägnantere Möglichkeit, foo=timmer(foo) zu ersetzen, indem @timmer verwendet wird, was in Python als syntaktischer Zucker bezeichnet wird.


import time
def timmer(func):
 def wrapper():
  """计时功能"""
  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():
 """打印"""
 time.sleep(2)
 print("Hello boy!")
foo()
Nach dem Login kopieren

Lassen Sie uns den Ausführungsprozess der Funktion Schritt für Schritt analysieren:

1. Importieren Sie das Zeitmodul


import time
Nach dem Login kopieren

2. Durch Definieren der Funktion wird der Code in der Funktion


def timmer(func):
Nach dem Login kopieren
Nach dem Login kopieren

3 nicht ausgeführt Dekorator, ganz Für foo=timer(foo) wird die Funktion foo als Parameter an die Funktion timmer übergeben


@timmer
Nach dem Login kopieren

4. Führen Sie die Funktion timmer aus und akzeptieren Sie die Parameter func=foo


def timmer(func):
Nach dem Login kopieren
Nach dem Login kopieren

5. Innerhalb des Funktions-Timmers wird der Funktions-Wrapper definiert, der Code innerhalb der Wrapper-Funktion wird nicht ausgeführt und dann der Funktions-Wrapper wird als Rückgabewert zurückgegeben


return wrapper
Nach dem Login kopieren

6 Weisen Sie foo den Rückgabewert zu. Merken Sie sich ihn in Schritt 3 🎜>


7. Führen Sie die Funktion foo() aus, aber die Funktion hier ist nicht mehr die ursprüngliche Funktion. Ja, weil wir den Wrapper an foo übergeben haben Rückgabewert vorher, also führt das Ausführen von foo den Wrapper aus. Ihre Speicheradressen sind also gleich, sodass sie alle auf denselben Adressraum verweisen:
@timmer #等于 foo=timmer(foo)
Nach dem Login kopieren


8. Führen Sie den Funktionswrapper aus, zeichnen Sie die Startzeit auf und führen Sie die Funktion func aus. Beim Ausführen von func wird die ursprüngliche Funktion foo ausgeführt 2 Sekunden und druckt die Zeichenfolge;
<function timmer.<locals>.wrapper at 0x00000180E0A8A950> #打印foo的结果
<function timmer.<locals>.wrapper at 0x000001F10AD8A950> #打印wrapper的结果
foo()
Nach dem Login kopieren


9. Notieren Sie die Endzeit, drucken Sie die Laufzeit aus und das Programm endet.
time_start=time.time()
 time.sleep(2)
 print("Hello boy!")
Nach dem Login kopieren


Hello boy!
Run time is 2.000161
Nach dem Login kopieren

ParameterdekoratorIm vorherigen Beispiel hat die ursprüngliche Funktion keine Parameter. Schauen wir uns an, wie man die Dekoratorfunktion ändert, wenn die ursprüngliche Funktion Parameter hat.


Wenn die ursprüngliche Funktion Parameter übergeben muss, hat my_max in diesem Beispiel zwei Positionen, die übergeben werden müssen. Sie müssen nur zwei Parameter hinzufügen der Wrapper. Formale Parameter, in diesem Beispiel ist es auch möglich, variable Parameter (*args, **kwargs) zu verwenden, was gleich my_max(1,2)=timmer(my_max)
import time
def timmer(func):
 def wrapper(*args,**kwargs):
  """计时功能"""
  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):
 """返回两个值的最大值"""
 res=x if x > y else y
 time.sleep(2)
 return res
res=my_max(1,2)
print(res)
#运行结果
Run time is 2.000175
Nach dem Login kopieren
<🎜 ist > Machen wir es als nächstes. Schauen Sie sich einen

Decorator mit Parametern an:


Wenn der Decorator selbst Parameter hat, einen Lassen Sie uns den Ausführungsprozess Schritt für Schritt analysieren:

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 == &#39;123456&#39; and username == &#39;Frank&#39;:
     print("Login successful")
     func()
    else:
     print("login error!")
   if filetype == &#39;SQL&#39;:
    print("No SQL")
  return wrapper
 return auth2
@auth(filetype=&#39;file&#39;) #先先返回一个auth2 ==》@auth2 ==》 index=auth2(index) ==》 index=wrapper
def index():
 print("Welcome to China")
index()
Nach dem Login kopieren
1 Definieren Sie die Funktionsauthentifizierung


2. Führen Sie zuerst die Funktion auth(filetype='file') aus

def auth(filetype):
Nach dem Login kopieren


3. Führen Sie die Funktion auth aus, definieren Sie eine Funktion auth2 und geben Sie sie als Rückgabewert zurück. dann entspricht dieses @auth (filetype='file') @auth2, was index=auth2(index)

@auth(filetype=&#39;file&#39;)
Nach dem Login kopieren



4 entspricht. auth2(index)-Ausführung, func=index, definieren Sie den Funktions-Wrapper und geben Sie ihn zurück. Zu diesem Zeitpunkt entspricht der Index tatsächlich dem Wrapper

def auth(filetype):
 def auth2(func):
  def wrapper(*args,**kwargs):
  return wrapper
 return auth2
Nach dem Login kopieren


5 Index, führen Sie den Wrapper aus und führen Sie die Funktion aus. Interner Code, filetype=="file", fordert den Benutzer auf, den Benutzernamen und das Passwort auszugeben, und stellt fest, ob die Eingabe korrekt ist. Wenn sie korrekt ist, wird die Funktion func() ausgeführt entspricht dem Ausführen des Originalindex und dem Drucken

def wrapper(*args,**kwargs):
return wrapper
Nach dem Login kopieren


6. Führen Sie den Ergebnistest aus

if filetype == "file":
    username=input("Please input your username:")
    passwd=input("Please input your password:")
    if passwd == &#39;123456&#39; and username == &#39;Frank&#39;:
     print("Login successful")
     func()
Nach dem Login kopieren

Please input your username:Frank
Please input your password:123456
Login successful
Welcome to China
Nach dem Login kopieren

装饰器也是可以被叠加的:


import time
#
def timmer(func):
 def wrapper():
  """计时功能"""
  time_start=time.time()
  func()
  time_end=time.time()
  print("Run time is %f "%(time_end-time_start))
  # print("---",wrapper)
 return wrapper
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 == &#39;123456&#39; and username == &#39;Frank&#39;:
     print("Login successful")
     func()
    else:
     print("login error!")
   if filetype == 'SQL':
    print("No SQL")
  return wrapper
 return auth2
@timmer
@auth(filetype=&#39;file&#39;) #先先返回一个auth2 ==》@auth2 ==》 index=auth2() ==》 index=wrapper
def index():
 print("Welcome to China")
index()

#测试结果
Please input your username:Frank
Please input your password:123456
Login successful
Welcome to China
Run time is 7.966267
Nach dem Login kopieren

注释优化


import time
def timmer(func):
 def wrapper():
  """计算程序运行时间"""
  start_time=time.time()
  func()
  end_time=time.time()
  print("Run time is %s:"%(end_time-start_time))
 return wrapper
@timmer
def my_index():
 """打印欢迎"""
 time.sleep(1)
 print("Welcome to China!")
my_index()
print(my_index.__doc__)

#运行结果
Welcome to China!
Run time is 1.0005640983581543:
计算程序运行时间
Nach dem Login kopieren

当我们使用了装饰器的时候,虽然没有修改代码本身,但是在运行的时候,比如上面这个例子,运行my_index其实在运行wrapper了,如果我们打印my_index的注释信息,会打印wrapper()的注释信息,那么该怎么优化?

可以在模块functools中导入wraps,具体见以下:


import time
from functools import wraps
def timmer(func):
 @wraps(func)
 def wrapper():
  """计算程序运行时间"""
  start_time=time.time()
  func()
  end_time=time.time()
  print("Run time is %s:"%(end_time-start_time))
 return wrapper
@timmer
def my_index():
 """打印欢迎"""
 time.sleep(1)
 print("Welcome to China!")
my_index()
print(my_index.__doc__)
#运行结果
Welcome to China!
Run time is 1.0003223419189453:
打印欢迎
Nach dem Login kopieren

这样,在表面看来,原函数没有发生任何变化。

为什么要用迭代器

从字面意思,迭代就是重复反馈过程的活动,其目的通常是为了比较所需目标或结果,在python中可以用迭代器来实现,先来描述一下迭代器的优缺点,如果看不懂可以先略过,等看完本博客再回头看,相信你会理解其中的意思:

优点:

迭代器在取值的时候是不依赖于索引的,这样就可以遍历那些没有索引的对象,比如字典和文件

迭代器与列表相比,迭代器是惰性计算,更节省内存

缺点:

无法获取迭代器的长度,没有列表灵活

只能往后取值,不能倒着取值

什么是迭代器

那么在python什么才算是迭代器呢?

只要对象有__iter__(),那么它就是可迭代的,迭代器可以使用函数next()来取值

下面我们来看一个简单的迭代器:


my_list=[1,2,3]
li=iter(my_list)  #li=my_list.__iter__()
print(li)
print(next(li))
print(next(li))
print(next(li))
#运行结果
<list_iterator object at 0x000002591652C470>
2
Nach dem Login kopieren

可以看到,使用内置函数iter可以将列表转换成一个列表迭代器,使用next()获取值,一次值取一个值,当值取完了,再使用一次next()的时候,会报异常StopIteration,可以通过异常处理的方式来避免,try-except-else就是一个最常用的异常处理结构:


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
Nach dem Login kopieren

查看可迭代对象和迭代器对象

使用Iterable模块可以判断对象是否是可迭代的:


from collections import Iterable
s="hello" #定义字符串
l=[1,2,3,4] #定义列表
t=(1,2,3) #定义元组
d={&#39;a&#39;:1} #定义字典
set1={1,2,3,4} #定义集合
f=open("a.txt") #定义文本
# 查看是否都是可迭代的
print(isinstance(s,Iterable))
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(set1,Iterable))
print(isinstance(f,Iterable))
#运行结果
True
True
True
True
True
True
Nach dem Login kopieren

通过判断,可以确定我们所知道的常用的数据类型都是可以被迭代的。

使用Iterator模块可以判断对象是否是迭代器:


from collections import Iterable,Iterator
s="hello"
l=[1,2,3,4]
t=(1,2,3)
d={&#39;a&#39;:1}
set1={1,2,3,4}
f=open("a.txt")
# 查看是否都是可迭代的
print(isinstance(s,Iterator))
print(isinstance(l,Iterator))
print(isinstance(t,Iterator))
print(isinstance(d,Iterator))
print(isinstance(set1,Iterator))
print(isinstance(f,Iterator))
#运行结果
False
False
False
False
False
True
Nach dem Login kopieren

可知只有文件是迭代器,所以可以直接使用next(),而不需要转换成迭代器。

什么是生成器

生产器就是一个是带有yield的函数

下面来看一个简单的生成器


def my_yield():
 print(&#39;first&#39;)
 yield 1
g=my_yield()
print(g)
#运行结果
<generator object my_yield at 0x0000024366D7E258>
Nach dem Login kopieren

生成器也是一个迭代器


from collections import Iterator
def my_yield():
 print(&#39;first&#39;)
 yield 1
g=my_yield()
print(isinstance(g,Iterator))
#运行结果
True
Nach dem Login kopieren

那就可以用next()来取值了


print(next(g))
#运行结果
first
1
Nach dem Login kopieren

生成器的执行过程

我们来看以下下面这个例子,了解生产的执行流程


def my_yield():
 print(&#39;first&#39;)
 yield 1
 print(&#39;second&#39;)
 yield 2
 print(&#39;Third&#39;)
 yield 3
g=my_yield()
next(g)
next(g)
next(g)
#运行结果
first
second
Third
Nach dem Login kopieren

1.定义生成器my_yield,并将其赋值给了g


def my_yield():
g=my_yield()
Nach dem Login kopieren

2.开始第一次执行next(),开始执行生产器函数 ,打印第一语句,遇到yileld的时候暂停,并返回一个1,如果你想打印返回值的话,这里会显示1


 print(&#39;first&#39;)
 yield 1
Nach dem Login kopieren

3.再执行2次,打印字符串(每执行一次都会暂停一下)


 print(&#39;second&#39;)
 yield 2
 print(&#39;Third&#39;)
 yield 3
Nach dem Login kopieren

4.如果再加一次next()就会报出StopIteration异常了

生成器在每次暂停的时候,函数的状态将被保存下来,来看下面的例子:


def foo():
 i=0
 while True:
  yield i
  i+=1
g=foo()
for num in g:
 if num < 10:
  print(num)
 else:
  break
#运行结果
Nach dem Login kopieren

for循环中隐含next(),每next一次,暂停一次,if语句判断一次,然后执行下一次next,可以看到我们的while循环并没有无限循环下去,而是状态被保存下来了。

协程函数

我们来看下面这个生成器和执行结果


def eater(name):
 print(&#39;%s start to eat food&#39;%name)
 while True:
  food=yield
  print(&#39;%s get %s ,to start eat&#39;%(name,food))
 print(&#39;done&#39;)
e=eater(&#39;Frank&#39;)
next(e)
e.send(&#39;egg&#39;) #给yield送一个值,并继续执行代码
e.send(&#39;tomato&#39;)
#运行结果
Frank start to eat food
Frank get egg ,to start eat
Frank get tomato ,to start eat
Nach dem Login kopieren

send可直接以向yield传值,含有yield表达式的函数我们也称为协程函数,

这运行程序的时候,不可以直接send,必须先使用next()初始化生成器。

如果存在多个这样的函数,那么我们每次执行的时候都要去next()一下,为了防止忘记这一步操作,可以使用装饰器初始化:


def init(func):
 def wrapper(*args):
  res = func(*args)
  next(res)  # 在这里执行next
  return res
 return wrapper
@init
def eater(name):
 print(&#39;%s start to eat food&#39;%name)
 while True:
  food=yield
  print(&#39;%s get %s ,to start eat&#39;%(name,food))
 print(&#39;done&#39;)
e=eater(&#39;Frank&#39;)
e.send(&#39;egg&#39;) 
e.send(&#39;tomato&#39;)
Nach dem Login kopieren

所以在程序中有更多的生成器需要初始化的时候,直接调用这个装饰器就可以了。

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung von Beispielen für Dekoratoren, Iteratoren und Generatoren in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage