0

我是一个 python 菜鸟,我正在尝试以“pythonic”的方式解决我的问题。我有一个类,谁的__init__方法需要 6 个参数。如果有任何验证失败,我需要验证每个参数并抛出/引发异常。

这是正确的方法吗?

class DefinitionRunner:
    def __init__(self, canvasSize, flightId, domain, definitionPath, harPath):
        self.canvasSize = canvasSize
        self.flightId   = flightId
        self.domain     = domain
        self.harPath    = harPath
        self.definitionPath = definitionPath

        ... bunch of validation checks...
        ... if fails, raise ValueError ...
4

5 回答 5

3

如果您希望变量可以独立于 设置__init__,您可以使用属性在单独的方法中实现验证。

它们仅适用于新样式类,因此您需要将类定义为class DefinitionRunner(object)

例如,

    @property
    def canvasSize(self):
        return self._canvasSize

    @canvasSize.setter
    def canvasSize(self, value):
        # some validation here
        self._canvasSize = value
于 2013-01-23T20:12:21.633 回答
1

从广义上讲,这看起来像你这样做的方式。虽然严格来说,您最好在分配之前而不是之后进行验证,特别是如果分配可能是时间或资源密集型的。此外,风格约定说不要像你一样对齐分配块。

于 2013-01-23T20:09:20.550 回答
1

我会像你那样做。除了验证的东西。我将在 setter 方法中进行验证并使用它来设置属性。

于 2013-01-23T20:11:30.790 回答
1

你可以做这样的事情。为每种类型的输入创建一个验证器。创建一个辅助函数来运行验证:

def validate_and_assign(obj, items_d, validators):
    #validate all entries
    for key, validator in validators.items():
        if not validator[key](items_d[key]):
            raise ValueError("Validation for %s failed" % (key,))

    #set all entries
    for key, val in items_d.items():
        setattr(obj, key, val)

你会像这样使用它:

class DefinitionRunner:
    validators = {
        'canvasSize': canvasSize_validator,
        'flightId': flightId_validator,
        'domain': domain_validator,
        'definitionPath': definitionPath_validator,
        'harPath': harPath_validator,
    }

    def __init__(self, canvasSize, flightId, domain, definitionPath, harPath):
        validate_and_assign(self, {
            'canvasSize': canvasSize,
            'flightId': flightId,
            'domain': domain,
            'definitionPath': definitionPath,
            'harPath': harPath,
        }, DefinitionRunner.validators) 

当然,如果数据类型相同,验证器可能是相同的函数。

于 2013-01-23T20:26:18.913 回答
1

我不确定这是否完全是“Pythonic”,但我已经定义了一个名为 require_type 的函数装饰器。(老实说,我想我是在网上某个地方找到的。)

def require_type(my_arg, *valid_types):
'''
    A simple decorator that performs type checking.

    @param my_arg: string indicating argument name
    @param valid_types: list of valid types
'''
def make_wrapper(func):
    if hasattr(func, 'wrapped_args'):
        wrapped = getattr(func, 'wrapped_args')
    else:
        body = func.func_code
        wrapped = list(body.co_varnames[:body.co_argcount])

    try:
        idx = wrapped.index(my_arg)
    except ValueError:
        raise(NameError, my_arg)

    def wrapper(*args, **kwargs):

        def fail():
            all_types = ', '.join(str(typ) for typ in valid_types)
            raise(TypeError, '\'%s\' was type %s, expected to be in following list: %s' % (my_arg, all_types, type(arg)))

        if len(args) > idx:
            arg = args[idx]
            if not isinstance(arg, valid_types):
                fail()
        else:
            if my_arg in kwargs:
                arg = kwargs[my_arg]
                if not isinstance(arg, valid_types):
                    fail()

        return func(*args, **kwargs)

    wrapper.wrapped_args = wrapped
    return wrapper
return make_wrapper

然后,使用它:

class SomeObject(object):

    @require_type("prop1", str)
    @require_type("prop2", numpy.complex128)
    def __init__(self, prop1, prop2):
        pass
于 2013-01-23T22:25:03.860 回答