Es ist ein gängiger Prozess, Daten zu verarbeiten, einmal auf einer Festplatte zu speichern und wiederzuverwenden (Datenverarbeitung ab dem zweiten Mal überspringen), wobei jedoch die Abhängigkeit der Parameter zum Zeitpunkt der Wiederverwendung usw. berücksichtigt wird. Es neigt dazu, unerwartet kompliziert zu sein. Stellen Sie sich daher eine Implementierung vor, die nicht denselben Vorgang wiederholt, indem Sie mit einem Python-Dekorator ein Urteil überspringen.
Eine Bibliothek dieses Prozesses finden Sie unter github.com/sotetsuk/memozo:
Angenommen, Sie haben jetzt eine große Menge an Anweisungsdaten (ein Satz pro Zeile):
1. I have a pen.
2. I have an apple.
3. ah! Apple pen!
...
9999...
# PPAP (copyright belongs to Pikotaro)
Angenommen, Sie möchten nur die Sätze, die ein bestimmtes Schlüsselwort enthalten, aus diesen Daten herausfiltern (z. B. den Satz, der das Schlüsselwort `` `pen``` enthält).
Eine naive Implementierung des Filters wäre die Erstellung eines Generators, der jedes Mal liefert, wenn er eine Aussage findet, die die Kriterien erfüllt:
def filter_data(keyword):
path_to_raw_data = './data/sentences.txt'
with codecs.open(path_to_raw_data, 'r', 'utf-8') as f:
for line in f:
if keyword in line:
yield line
gen = filter_data('pen')
for line in gen:
print(line, end='')
Und wenn diese verarbeiteten Daten (gefilterte Daten) viele Male wiederverwendet werden, ist es nicht immer eine gute Idee, jedes Mal alle Daten zu scannen.
Möglicherweise möchten Sie die gefilterten Daten einmal auf der Festplatte zwischenspeichern und dann die zwischengespeicherten Daten verwenden.
Dieser Datenverarbeitungsprozess hängt auch vom Parameter (`` Schlüsselwort `) ab. Wenn dieser Prozess also mit einem anderen` `Schlüsselwort
ausgeführt wird, werden alle Daten erneut überprüft und auf die Festplatte gelegt. Es gibt auch den Aspekt, zwischenspeichern zu wollen.
Und ich habe den Wunsch, diesen Prozess einfach durch Umwickeln der Funktion mit einem Dekorateur zu erreichen.
Zusammenfassend ist das Ziel, die Ausgabe vom Generator mit dem Dekorator `` `awesome_decorator``` wie folgt zwischenzuspeichern. Wenn diese Funktion mit denselben Parametern ausgeführt wird, verwenden Sie den Cache, um die Ausgabe zurückzugeben. ist:
@awesome_decorator
def filter_data(keyword):
path_to_raw_data = './data/sentences.txt'
with codecs.open(path_to_raw_data, 'r', 'utf-8') as f:
for line in f:
if keyword in line:
yield line
#Beim ersten Mal werden alle Daten gescannt und das Ergebnis zurückgegeben.
#Zu diesem Zeitpunkt die gefilterte Anweisung'./data/pen.txt'Cache an.
gen_pen_sentences1 = filter_data('pen')
for line in gen_pen_sentences1:
print(line, end='')
#Da es mit den gleichen Parametern ausgeführt wird, wird der Cache'./data/pen.txt'Gibt die Daten von zurück.
gen_pen_sentences2 = filter_data('pen')
for line in gen_pen_sentences2:
print(line, end='')
#Da es sich um einen neuen Parameter handelt, werden wir ihn erneut aus den Rohdaten filtern.
gen_apple_sentences = filter_data('apple')
for line in gen_apple_sentences:
print(line, end='')
Auch dieses Beispiel ist eine Funktion, die einen Generator zurückgibt. Es kann jedoch auch andere Situationen geben, in denen Sie das Ausführungsergebnis einer Funktion zwischenspeichern möchten, die ein Objekt zurückgibt, das von `pickle``` auf die Festplatte serialisiert werden kann (z. B. vorverarbeitet).
`ndarray``` und parameterabhängig trainierte maschinelle Lernmodelle).
awesome_decorator
Ist einfach zu implementieren, stellen Sie fest, ob bereits zwischengespeicherte Dateien vorhanden sind.
Nur (auch wenn Sie "Gurke" usw. verwenden):
def awesome_decorator(func):
@functools.wraps(func)
def _wrapper(keyword):
#Dieses Mal nehmen wir der Einfachheit halber an, dass das Argument der Funktion nur ein Schlüsselwort ist.
#Allgemeines(*args, **kwargs)Verwenden Sie bei der Verwendung inspect usw., um die Argumente und ihre Werte zu extrahieren.
file_path = './data/{}.txt'.format(keyword)
#Wenn zwischengespeicherte Daten vorhanden sind, wird ein Generator zurückgegeben, der Anweisungen daraus liest.
if os.path.exists(file_path):
def gen_cached_data():
with codecs.open(file_path, 'r', 'utf-8') as f:
for line in f:
yield line
return gen_cached_data()
#Wenn keine zwischengespeicherten Daten vorhanden sind, wird ein Dekorator generiert, der wie gewohnt eine Anweisung aus den Rohdaten zurückgibt.
gen = func(keyword)
#Außerdem werden die von den oben genannten Generatoren zurückgegebenen Werte zwischengespeichert.
def generator_with_cache(gen, file_path):
with codecs.open(file_path, 'w', 'utf-8') as f:
for e in gen:
f.write(e)
yield e
return generator_with_cache(gen, file_path)
return _wrapper
Zur Erläuterung des Dekorators selbst ist der Artikel 12 Schritte zum Verständnis von Python-Dekoratoren leicht zu verstehen.
Alles in allem sieht es so aus (dies funktioniert gut mit `` `. / Data / satz.txt```):
awesome_generator.py
# -*- coding: utf-8 -*-
import os
import functools
import codecs
def awesome_decorator(func):
@functools.wraps(func)
def _wrapper(keyword):
#Dieses Mal nehmen wir der Einfachheit halber an, dass das Argument der Funktion nur ein Schlüsselwort ist.
#Allgemeines(*args, **kwargs)Verwenden Sie bei der Verwendung inspect usw., um die Argumente und ihre Werte zu extrahieren.
file_path = './data/{}.txt'.format(keyword)
#Wenn zwischengespeicherte Daten vorhanden sind, wird ein Generator zurückgegeben, der Anweisungen daraus liest.
if os.path.exists(file_path):
def gen_cached_data():
with codecs.open(file_path, 'r', 'utf-8') as f:
for line in f:
yield line
return gen_cached_data()
#Wenn keine zwischengespeicherten Daten vorhanden sind, wird ein Dekorator generiert, der wie gewohnt eine Anweisung aus den Rohdaten zurückgibt.
gen = func(keyword)
#Außerdem werden die von den oben genannten Generatoren zurückgegebenen Werte zwischengespeichert.
def generator_with_cache(gen, file_path):
with codecs.open(file_path, 'w', 'utf-8') as f:
for e in gen:
f.write(e)
yield e
return generator_with_cache(gen, file_path)
return _wrapper
@awesome_decorator
def filter_data(keyword):
path_to_raw_data = './data/sentences.txt'
with codecs.open(path_to_raw_data, 'r', 'utf-8') as f:
for line in f:
if keyword in line:
yield line
if __name__ == '__main__':
#Beim ersten Mal werden alle Daten gescannt und das Ergebnis zurückgegeben.
#Zu diesem Zeitpunkt die gefilterte Anweisung'./data/pen.txt'Cache an.
gen_pen_sentences1 = filter_data('pen')
for line in gen_pen_sentences1:
print(line, end='')
#Da es mit den gleichen Parametern ausgeführt wird, wird der Cache'./data/pen.txt'Gibt die Daten von zurück.
gen_pen_sentences2 = filter_data('pen')
for line in gen_pen_sentences2:
print(line, end='')
#Da es sich um einen neuen Parameter handelt, werden wir ihn erneut aus den Rohdaten filtern.
gen_apple_sentences = filter_data('apple')
for line in gen_apple_sentences:
print(line, end='')
memozo 今回の実装は,パラメータの形やファイル名等を固定された形で扱っていましたが,任意の形に少し拡張したものをパッケージとしてgithub.com/sotetsuk/memozoにまとめました. Damit kann dieser Prozess folgendermaßen geschrieben werden:
from memozo import Memozo
m = Memozo('./data')
@m.generator(file_name='filtered_sentences', ext='txt')
def filter_data(keyword):
path_to_raw_data = './data/sentences.txt'
with codecs.open(path_to_raw_data, 'r', 'utf-8') as f:
for line in f:
if keyword in line:
yield line
Die Cache-Datei wird in `./ data / filtered_sentences_1fec01f.txt '` `gespeichert, und der Verlauf der in
. / Data / .memozo``` verwendeten Parameter wird geschrieben.
Der Hash wird berechnet aus (Dateiname, Funktionsname, Parameter). Wenn sowohl der Verlauf als auch die Cache-Datei, die denselben Hash verwenden, bereits vorhanden sind, wird die Funktionsausführung übersprungen.
Mit anderen Worten, wenn Sie mit demselben (Dateiname, Funktionsname, Parameter) ausführen, wird der Wert aus dem Cache zurückgegeben, und wenn Sie einen ändern, ist das Ergebnis anders.
Zusätzlich zum Generator gibt es Versionen von Funktionen, die `pickle```,`
codecs und gewöhnlichen `` `open
entsprechen.
Ich denke, die Implementierung ist noch unvollständig, daher wäre ich Ihnen dankbar, wenn Sie Issue / PR usw. erwähnen könnten.
タスク間に複雑な依存関係がある場合はDAGベースのワークフローツールを使った方がいいでしょう.一例として,github.com/spotify/luigiなどが挙げられます.