Kontextmanager zur Bestätigung von Daten

Ich versuche, eine gute Lösung zu machen, und nichts kommt in den Sinn. Als Übung versuche ich, einen Kontext-Manager zu erstellen, der die Datenvalidierung verarbeitet, so etwas wie:

validation = lambda x: len(x) <= 10 with validator(validation): some_data = input("Please enter a name of 10 characters or less: ") print(some_data) # OUTPUT >> Please enter a name of 10 characters or less: FooBarSpamEggs >> Please enter a name of 10 characters of less: Adam Adam 

Ursprünglich dachte ich darüber nach, dies mit unittest.mock.patch tun, aber ich merkte, dass ich die ursprüngliche Funktion nicht anrufen kann, während es gepatched ist, zB:

 def patched(validation, *args): while True: p = __builtins__.input(args) # Doesn't work if validation(p): break return p with unittest.mock.patch('builtins.input', patched): input("Some prompt here: ") # fails on recursion error as patched calls itself 

Dann dachte ich, einen Dekorateur zu schreiben, um eine einzelne Zeile zu validieren, aber das ist wirklich nur nützlich, wenn man so etwas machen könnte:

 @validate(lambda x: int(x) == 6) p = input("How many sides does a d6 have? ") # can't decorate a function call 

Ich bin auf diese Kontext-Manager-Idee aufgehängt. Leider weiß ich nicht, ob ein Kontextmanager Zugang zu seinem Inhalt hat oder wenn er nur auf seine Argumente beschränkt ist. Irgendwelche Gedanken?

Abgesehen davon weiß ich, dass ich diese Funktionalität in einer Funktion machen könnte:

 def validate_input(prompt, validation, msg_if_fail=None): while True: p = input(prompt) if validation(p): break if msg_if_fail is not None: print(msg_if_fail) return p 

Aber es ist nicht so hübsch Dies ist, wie gesagt, eine Übung mehr als ein praktisches Problem.

2 Solutions collect form web for “Kontextmanager zur Bestätigung von Daten”

Sie könnten einen regulären Kontext-Manager verwenden, um unittest.mock.patch zu verpacken, und speichern Sie eine Referenz die ursprüngliche input vor dem Patching. Dann können Sie die ursprüngliche input an Ihre patched Funktion übergeben:

 import unittest.mock import contextlib from functools import partial def patched(validation, orig_input, *args): while True: p = orig_input(*args) if validation(p): break return p @contextlib.contextmanager def validator(validate_func): func = partial(patched, validate_func, input) # original input reference saved here patch = unittest.mock.patch('builtins.input', func) patch.start() try: yield finally: patch.stop() validation = lambda x: len(x) <= 10 

Dann können Sie den Contextmanager wie folgt nutzen:

 with validator(validation): x = input("10 or less: ") x = input("10 or less (unpatched): ") print("done") 

Probenausgabe:

 10 or less: abcdefghijklmnop 10 or less: abcdefgdfgdgd 10 or less: abcdef 10 or less (unpatched): abcdefghijklmnop done 

Ein Dekorateur, der Parameter akzeptiert, könnte es ziemlich nett machen ( http://www.artima.com/weblogs/viewpost.jsp?thread=240845 ):

 max10 = lambda x: len(x) <= 10 def validator(test): def wrap(func): def wrapped(*args, **kwargs): result = func(*args, **kwargs) if test(result): return result return None return wrapped return wrap 

Der regelmäßige Weg, es zu benutzen:

 @validator(max10) def valid_input(prompt="Please enter a name: "): return raw_input(prompt) print valid_input() 

Die Anwendung des Dekorateurs sieht manuell näher, was du verlangst:

 valid_input = validator(max10)(raw_input) print valid_input("Please enter a name: ") 
Python ist die beste Programmiersprache der Welt.