Maison  >  Article  >  développement back-end  >  Introduction à l'utilisation du mot-clé rendement en python (exemple de code)

Introduction à l'utilisation du mot-clé rendement en python (exemple de code)

不言
不言avant
2018-12-15 10:09:442520parcourir

Cet article vous apporte une introduction à l'utilisation du mot-clé rendement en Python (exemples de code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.

yield est un mot-clé en python. Lorsque je suis entré en contact avec python pour la première fois, je ne comprenais pas ce mot-clé. Ce n'est qu'après l'avoir maîtrisé que j'ai réalisé que cet article était très utile. va déterminer comment utiliser le rendement .

1 Utilisez rendement pour créer un générateur

En python, un générateur est un objet itérable, mais un objet itérable n'est pas nécessairement un générateur.
Par exemple, la liste est un objet itérable

>>> a = list(range(3))
>>> for i in a:
    print(i)
0
1
2
3

Mais toutes les valeurs d'un objet liste sont stockées en mémoire Si la quantité de données est très importante, la mémoire peut ne pas être suffisante. ; this Dans ce cas, vous pouvez générer un générateur. Par exemple, Python peut utiliser "()" pour construire un objet générateur :

>>> b = (x for x in range(3))
>>> for i in b:
    print(i)

0
1
2
>>> for i in b:
    print(i)
    
>>>

Le générateur peut être itéré et les données sont générées en réel. temps, et ne seront pas tous enregistrés en mémoire. Il est à noter que le générateur ne peut être lu qu'une seule fois. Comme vous pouvez le voir à partir des résultats d'exécution ci-dessus, le résultat de sortie de la deuxième boucle for est vide. >.

Dans la programmation réelle, si une fonction doit générer une donnée sérialisée, le moyen le plus simple est de mettre tous les résultats dans une liste et de la renvoyer. Si la quantité de données est importante, vous devriez envisager de l'utiliser. un générateur Pour réécrire une fonction qui renvoie directement une liste (Effective Python, Item 16

>>> def get_generator():
    for i in range(3):
        print('gen ', i)
        yield i
        
>>> c = get_generator()    
>>> c = get_generator()
>>> for i in c:
    print(i)
    
gen  0
0
gen  1
1
gen  2
2
Comme le montre le code ci-dessus, lorsque la fonction get_generator est appelée, le code à l'intérieur de la fonction le fera). ne sera pas exécuté, mais renverra Un objet itérateur est obtenu et le code de la fonction ne sera exécuté que lors d'une itération avec une boucle for.

En plus d'utiliser une boucle for pour obtenir la valeur renvoyée par le générateur, vous pouvez également utiliser next et send

>>> c = get_generator()
>>> print(next(c))
gen  0
0
>>> print(next(c))
gen  1
1
>>> print(next(c))
gen  2
2
>>> print(next(c))
Traceback (most recent call last):
  File "<pyshell#59>", line 1, in <module>
    print(next(c))
StopIteration
>>> c = get_generator()
>>> c.send(None)
gen  0
0
>>> c.send(None)
gen  1
1
>>> c.send(None)
gen  2
2
>>> c.send(None)
Traceback (most recent call last):
  File "<pyshell#66>", line 1, in <module>
    c.send(None)
StopIteration

Une fois le résultat du générateur lu, une exception StopIteration sera générée.

2 Utilisation de

yield dans les coroutines Un scénario d'utilisation courant consiste à implémenter des coroutines via le rendement. modèle à titre d'exemple :

# import logging
# import contextlib
# def foobar():
#     logging.debug('Some debug data')
#     logging.error('Some error data')
#     logging.debug('More debug data')
# @contextlib.contextmanager
# def debug_logging(level):
#     logger = logging.getLogger()
#     old_level = logger.getEffectiveLevel()
#     logger.setLevel(level)
#     try:
#         yield
#     finally:
#         logger.setLevel(old_level)
# with debug_logging(logging.DEBUG):
#     print('inside context')
#     foobar()
# print('outside context')
# foobar()
def consumer():
    r = 'yield'
    while True:
        print('[CONSUMER] r is %s...' % r)
        #当下边语句执行时,先执行yield r,然后consumer暂停,此时赋值运算还未进行
        #等到producer调用send()时,send()的参数作为yield r表达式的值赋给等号左边
        n = yield r #yield表达式可以接收send()发出的参数
        if not n:
            return # 这里会raise一个StopIteration
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'
def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)   #调用consumer生成器
        print('[PRODUCER] Consumer return: %s' % r)
    c.send(None)    
    c.close()
c = consumer()
produce(c)
[CONSUMER] r is yield...
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
Traceback (most recent call last):
  File ".\foobar.py", line 51, in <module>
    produce(c)
  File ".\foobar.py", line 47, in produce
    c.send(None)
StopIteration
Comme vous pouvez le voir dans l'exemple ci-dessus, l'expression de rendement coopère avec l'envoi de données d'échange

n = yield r
r = c.send(n)

3 contextmanager. Un autre scénario d'utilisation intéressant de

est dans contextmanager, comme suit :

import logging
import contextlib
def foobar():
    logging.debug('Some debug data')
    logging.error('Some error data')
    logging.debug('More debug data')
@contextlib.contextmanager
def debug_logging(level):
    logger = logging.getLogger()
    old_level = logger.getEffectiveLevel()
    logger.setLevel(level)
    try:
        yield #这里表示with块中的语句
    finally:
        logger.setLevel(old_level)
with debug_logging(logging.DEBUG):
    print('inside context')
    foobar()
print('outside context')
foobar()
inside context
DEBUG:root:Some debug data
ERROR:root:Some error data
DEBUG:root:More debug data
outside context
ERROR:root:Some error data
Dans le code ci-dessus, en utilisant le gestionnaire de contexte (contextmanager ), le niveau du journal est amélioré lorsque l'expression de rendement arrive. Yield représente l'instruction dans le bloc with

Résumé

L'expression de rendement peut créer un générateur, et vous devriez le faire. pensez à utiliser un générateur pour réécrire la fonction qui renvoie directement la liste

Étant donné que le générateur ne peut être lu qu'une seule fois, une attention particulière doit être portée lors de l'utilisation d'une boucle for pour parcourir si le générateur continue de lire après la lecture ; , une exception StopIteration sera levée. En fait, cette exception peut être utilisée en programmation comme base pour juger de la fin de la lecture

Un scénario d'utilisation courant de rendement consiste à implémenter des coroutines en coopérant avec l'envoi ; fonction, il peut obtenir l'effet d'échange de données ;

yield peut également représenter l'instruction dans le bloc with dans la fonction décorée par contextmanager

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer