编程语言
首页 > 编程语言> > python – 用于验证数据的上下文管理器

python – 用于验证数据的上下文管理器

作者:互联网

我正在努力考虑一个很好的解决方案,并没有想到任何事情.作为练习,我正在尝试创建一个将处理数据验证的上下文管理器,例如:

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

最初我想过用unittest.mock.patch做这个,但我意识到在修补时我不能调用原始函数,例如:

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

然后我考虑编写一个装饰器来验证一行,但是如果你可以这样做的话,那真的很有用:

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

不过,我对这个上下文管理器的想法很感兴趣.不幸的是,我不知道上下文管理器是否可以访问其内容,或者它是否仅限于其参数.有什么想法吗?

顺便说一句,我知道我可以在一个函数中呈现这个功能,例如:

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

但它并不那么漂亮.正如我所说,这是一项不仅仅是实际问题的练习.

解决方法:

您可以使用常规上下文管理器来包装unittest.mock.patch,并在修补之前保存对原始输入函数的引用.然后,您可以将原始输入传递给修补功能:

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

然后你可以像这样使用contextmanager:

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

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

样本输出:

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

标签:contextmanager,python,validation
来源: https://codeday.me/bug/20191002/1841770.html