Programing

클래스 인스턴스의 속성을 검증하는 올바른 접근 방식

lottogame 2020. 11. 2. 07:35
반응형

클래스 인스턴스의 속성을 검증하는 올바른 접근 방식


다음과 같은 간단한 Python 클래스가 있습니다.

class Spam(object):
    __init__(self, description, value):
        self.description = description
        self.value = value

다음 제약 조건을 확인하고 싶습니다.

  • "설명은 비워 둘 수 없습니다."
  • "값은 0보다 커야합니다."


1. 스팸 개체를 만들기 전에 데이터의 유효성을 검사 해야합니까 ?
2. __init__방법 에 대한 데이터를 확인 ?
3. is_validSpam 클래스에 메서드를 만들고 spam.isValid ()로 호출합니까?
4. is_validSpam 클래스에 정적 메서드를 만들고 Spam.isValid (description, value)?
5. setters 선언에 대한 데이터를 확인합니까?
6. 등

잘 디자인 된 / 파이 토닉 / 장황하지 않은 (많은 속성이있는 수업에서) / 우아한 접근 방식을 추천 해 주시겠습니까?


Python 속성사용 하여 각 필드에 개별적으로 규칙을 명확하게 적용하고 클라이언트 코드가 필드를 변경하려고 할 때에도 적용 할 수 있습니다.

class Spam(object):
    def __init__(self, description, value):
        self.description = description
        self.value = value

    @property
    def description(self):
        return self._description

    @description.setter
    def description(self, d):
        if not d: raise Exception("description cannot be empty")
        self._description = d

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, v):
        if not (v > 0): raise Exception("value must be greater than zero")
        self._value = v

__init__함수 내에서도 규칙을 위반하려는 모든 시도에서 예외가 발생하며이 경우 객체 생성이 실패합니다.

업데이트 : 2010 년과 지금 사이에 operator.attrgetter다음 사항에 대해 배웠습니다 .

import operator

class Spam(object):
    def __init__(self, description, value):
        self.description = description
        self.value = value

    description = property(operator.attrgetter('_description'))

    @description.setter
    def description(self, d):
        if not d: raise Exception("description cannot be empty")
        self._description = d

    value = property(operator.attrgetter('_value'))

    @value.setter
    def value(self, v):
        if not (v > 0): raise Exception("value must be greater than zero")
        self._value = v

개체가 생성 될 때만 값의 유효성을 검사하고 잘못된 값을 전달하는 것이 프로그래밍 오류로 간주되면 어설 션을 사용합니다.

class Spam(object):
    def __init__(self, description, value):
        assert description != ""
        assert value > 0
        self.description = description
        self.value = value

이것은 당신이 얻는 것만 큼 간결하며 이것이 객체를 만들기위한 전제 조건임을 명확하게 문서화합니다.


Unless you're hellbent on rolling your own, you can simply use formencode. It really shines with many attributes and schemas (just subclass schemas) and has a lot of useful validators builtin. As you can see this is the "validate data before creating spam object" approach.

from formencode import Schema, validators

class SpamSchema(Schema):
    description = validators.String(not_empty=True)
    value = validators.Int(min=0)

class Spam(object):
    def __init__(self, description, value):
        self.description = description
        self.value = value

## how you actually validate depends on your application
def validate_input( cls, schema, **input):
    data = schema.to_python(input) # validate `input` dict with the schema
    return cls(**data) # it validated here, else there was an exception

# returns a Spam object
validate_input( Spam, SpamSchema, description='this works', value=5) 

# raises an exception with all the invalid fields
validate_input( Spam, SpamSchema, description='', value=-1) 

You could do the checks during __init__ too (and make them completely transparent with descriptors|decorators|metaclass), but I'm not a big fan of that. I like a clean barrier between user input and internal objects.


if you want to only validate those values passed to the constructor, you could do:

class Spam(object):
    def __init__(self, description, value):
        if not description or value <=0:
            raise ValueError
        self.description = description
        self.value = value

This will of course will not prevent anyone from doing something like this:

>>> s = Spam('s', 5)
>>> s.value = 0
>>> s.value
0

So, correct approach depends on what you're trying to accomplish.

참고URL : https://stackoverflow.com/questions/2825452/correct-approach-to-validate-attributes-of-an-instance-of-class

반응형