Я нуб-питон, и я пытаюсь решить свои проблемы "питоническим" способом. У меня есть класс, метод которого __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 ...
0
mr-sk 24 Янв 2013 в 00:04

5 ответов

Лучший ответ

Вообще говоря, это похоже на то, как ты это сделаешь. Хотя, строго говоря, вы могли бы также выполнить проверку до, а не после назначения, особенно если назначение может быть потенциально длительным или ресурсоемким. Кроме того, соглашение о стиле говорит, что вы не должны выравнивать блоки назначения.

1
Silas Ray 23 Янв 2013 в 20:09

Я бы сделал это так, как ты. За исключением проверяющего материала. Я бы проверил в методе сеттера и использовал бы его, чтобы установить атрибуты.

1
fvosberg 23 Янв 2013 в 20:11

Если вы хотите, чтобы переменные устанавливались независимо от __init__, вы можете использовать свойства для реализации проверок в отдельных методах.

Они работают только для новых классов стилей, поэтому вам нужно определить класс как class DefinitionRunner(object)

Так, например,

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

    @canvasSize.setter
    def canvasSize(self, value):
        # some validation here
        self._canvasSize = value
3
mgilson 23 Янв 2013 в 20:13

Я не уверен, что это именно 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
1
BenDundee 23 Янв 2013 в 22:25

Вы могли бы сделать что-то вроде этого. Сделайте валидатор для каждого типа ввода. Сделайте вспомогательную функцию для запуска проверки:

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) 

Конечно, валидаторы могут быть одной и той же функцией, если тип данных одинаков.

1
Claudiu 23 Янв 2013 в 20:26