Índice | Sección anterior (6.1 Protocolo de iteración) | Sección siguiente (6.3 Productor / Consumidor)
6.2 iteración personalizada
Sitio web de reembolsos www.cpa5.cnEsta sección explora cómo personalizar iteraciones usando funciones de generador.
problema
Suponga que desea personalizar el modo de iteración.
Por ejemplo: Countdown:
>>> for x in countdown(10):
... print(x, end=' ')
...
10 9 8 7 6 5 4 3 2 1
>>>
Hay una forma sencilla de hacer esto.
Constructor
Un generador es una función que define la iteración:
def countdown(n):
while n > 0:
yield n
n -= 1
Ejemplo:
>>> for x in countdown(10):
... print(x, end=' ')
...
10 9 8 7 6 5 4 3 2 1
>>>
Cualquier uso de una yield
declaración de función conocida como generador.
El comportamiento de las funciones generadoras es diferente al de las funciones ordinarias. Llamar a una función generadora crea un objeto generador en lugar de ejecutar la función inmediatamente:
def countdown(n):
# Added a print statement
print('Counting down from', n)
while n > 0:
yield n
n -= 1
>>> x = countdown(10)
# There is NO PRINT STATEMENT
>>> x
# x is a generator object
<generator object at 0x58490>
>>>
La función de generador solo se __next__()
ejecuta cuando se llama al método:
>>> x = countdown(10)
>>> x
<generator object at 0x58490>
>>> x.__next__()
Counting down from 10
10
>>>
yield
Se genera un valor, pero se ejecuta la función de suspensión. Función de constructor en la siguiente llamada para __next__()
reanudar cuando el método (reanudar),
>>> x.__next__()
9
>>> x.__next__()
8
Cuando el generador devuelve el último valor, la iteración de nuevo provocará un error.
>>> x.__next__()
1
>>> x.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in ? StopIteration
>>>
Observación: El protocolo implementado por la función de generador es el mismo que el protocolo subyacente usado por la instrucción for en listas, tuplas, diccionarios y archivos.
Ejercicio
Ejercicio 6.4: Un generador simple
Si desea una iteración personalizada, siempre debe considerar las funciones del generador. La función del generador es fácil de escribir: cree una función necesaria para realizar la lógica iterativa y utilice el yield
valor de transmisión.
Por ejemplo, para crear un generador que encuentre subcadenas coincidentes en cada línea de un archivo:
>>> def filematch(filename, substr):
with open(filename, 'r') as f:
for line in f:
if substr in line:
yield line
>>> for line in open('Data/portfolio.csv'):
print(line, end='')
name,shares,price
"AA",100,32.20
"IBM",50,91.10
"CAT",150,83.44
"MSFT",200,51.23
"GE",95,40.37
"MSFT",50,65.10
"IBM",100,70.44
>>> for line in filematch('Data/portfolio.csv', 'IBM'):
print(line, end='')
"IBM",50,91.10
"IBM",100,70.44
>>>
Esta es una idea interesante: puede ocultar el procesamiento personalizado en una función y aplicar la función a un bucle for. El siguiente ejemplo explora una situación más inusual.
Ejercicio 6.5: Supervisar fuentes de datos de transmisión
El generador se puede utilizar para monitorear fuentes de datos en tiempo real (como archivos de registro, noticias del mercado de valores). En esta parte, exploraremos la idea de "usar generadores para monitorear fuentes de datos en tiempo real". Primero, siga estrictamente las instrucciones a continuación.
Data/stocksim.py
Para imitar los datos del mercado de valores, se seguirán escribiendo datos en tiempo real en el Data/stocklog.csv
archivo. Abra una ventana de línea de comando separada, ingrese al Data/
directorio y luego ejecute el stocksim.py
programa:
bash % python3 stocksim.py
Si está utilizando un sistema Windows, busque el stocksim.py
archivo y luego haga doble clic en el archivo para ejecutarlo. Entonces, dejemos eso a un lado para el programa (se ha estado ejecutando en eso), abra otra ventana de línea de comandos, vea que el programa de simulación está (traducción :) stocksim.py
escribiendo un Data/stocklog.csv
archivo de datos (traducción: si está usando un sistema Linux, puede, vaya al directorio de datos y luego use el tail -f stocklog.csv
comando para ver). Debería ver una nueva línea de texto que se agrega al Data/stocklog.csv
archivo cada pocos segundos . De manera similar, deje que el programa se ejecute en segundo plano; el programa se ejecutará durante unas horas (no se preocupe por esto).
stocksim.py
Después de ejecutar el programa, escribamos un programa para abrir Data/stocklog.csv
el archivo, movernos al final del archivo y ver la nueva salida. Cree el follow.py
archivo de directorio en el trabajo y coloque el siguiente código en el que:
# follow.py
import os
import time
f = open('Data/stocklog.csv')
f.seek(0, os.SEEK_END) # Move file pointer 0 bytes from end of file
while True:
line = f.readline()
if line == '':
time.sleep(0.1) # Sleep briefly and retry
continue
fields = line.split(',')
name = fields[0].strip('"')
price = float(fields[1])
change = float(fields[4])
if change < 0:
print(f'{name:>10s} {price:>10.2f} {change:>10.2f}')
Ejecute el follow.py
programa, verá cotizaciones de acciones en tiempo real (ticker de acciones). follow.py
El código en un sistema similar a Unix para ver el tail -f
comando del archivo de registro .
Nota: En este ejemplo, los readline()
métodos de uso y generalmente leen de un archivo con una realización ligeramente diferente (generalmente for
circular). En este caso, usamos readline()
el final para detectar archivos duplicados, para ver si se agregan nuevos datos (el readline()
método devuelve los nuevos datos o una cadena vacía).
Ejercicio 6.6: use generadores para generar datos
Ver el código del Ejercicio 6.5 encontrará que la primera parte del código para generar algunas líneas de datos, mientras que la while
circulación al final de la declaración de datos de consumo. Una de las principales características de los generadores es que puede mover el código que genera datos a funciones reutilizables.
6.5 Edite el código de práctica, para que a través de la función de generador se follow(filename)
lea el archivo de ejecución. Implemente los cambios para que funcione el siguiente código:
>>> for line in follow('Data/stocklog.csv'):
print(line, end='')
... Should see lines of output produced here ...
Modifique el código de cotización de acciones para que el código tenga el siguiente aspecto:
if __name__ == '__main__':
for line in follow('Data/stocklog.csv'):
fields = line.split(',')
name = fields[0].strip('"')
price = float(fields[1])
change = float(fields[4])
if change < 0:
print(f'{name:>10s} {price:>10.2f} {change:>10.2f}')
Ejercicio 6.7: Ver cartera de acciones
Modifique el follow.py
programa para que el programa pueda ver la transmisión de datos de acciones e imprimir la información de la cartera de acciones en esas acciones. Ejemplo:
if __name__ == '__main__':
import report
portfolio = report.read_portfolio('Data/portfolio.csv')
for line in follow('Data/stocklog.csv'):
fields = line.split(',')
name = fields[0].strip('"')
price = float(fields[1])
change = float(fields[4])
if name in portfolio:
print(f'{name:>10s} {price:>10.2f} {change:>10.2f}')
Nota: Para poder ejecutar este código, Portfolio
la clase debe ser compatible con el in
operador. Consulte el ejercicio 6.3 para asegurarse de que la Portfolio
clase implemente el __contains__()
operador.
discutir
Aquí, mueve un patrón iterativo interesante (líneas de lectura al final del archivo) a la función. follow()
Las funciones son ahora utilidades completamente universales que se pueden utilizar en cualquier programa. Por ejemplo, puede utilizar la follow()
función para ver el registro del servidor, el registro de depuración, similar a otras fuentes de datos.
Índice | Sección anterior (6.1 Protocolo de iteración) | Sección siguiente (6.3 Productor / Consumidor)
Nota: consulte https://github.com/codists/practical-python-zh para obtener la traducción completa