Python의 오리 타이핑, 데이터 유효성 검사 및 독단적 프로그래밍


10

오리 타이핑 정보 :

덕 타이핑은 습관적으로 메소드 및 함수 본문에서 인수 유형을 테스트하지 않고 문서화, 명확한 코드 및 올바른 사용을위한 테스트에 의존하여 도움을줍니다.

인수 검증 정보 (EAFP : 권한보다 용서를 구하는 것이 더 쉬움) 여기 에서 적합한 예 :

... 더 많은 파이썬으로 간주됩니다.

def my_method(self, key):
    try:
        value = self.a_dict[member]
    except TypeError:
        # do something else

즉, 코드를 사용하는 다른 사람은 실제 사전이나 서브 클래스를 사용할 필요가 없습니다. 매핑 인터페이스를 구현하는 모든 객체를 사용할 수 있습니다.

불행히도 실제로 그렇게 간단하지 않습니다. 위 예제의 멤버가 정수일 경우 어떻게됩니까? 정수는 변경할 수 없으므로 사전 키로 사용하는 것이 합리적입니다. 그러나 이들은 시퀀스 유형 객체를 색인하는 데에도 사용됩니다. 멤버가 정수인 경우 예제 2에서는 사전뿐만 아니라 목록과 문자열도 살펴볼 수 있습니다.

독단적 프로그래밍 정보 :

어설 션은 버그를 잡기위한 목적으로 프로그램의 내부 상태가 프로그래머가 예상 한 상태인지 확인하는 체계적인 방법입니다. 특히 코드를 작성하거나 다른 프로그래머가 인터페이스를 남용하는 동안 만들어진 잘못된 가정을 포착하는 데 유용합니다. 또한 프로그래머의 가정을 명확하게하여 인라인 문서로 작동 할 수 있습니다. ( "명시 적 묵시적보다 낫다")

언급 된 개념은 때때로 충돌하기 때문에 데이터 유효성 검사를 전혀 수행하지 않거나 강력한 유효성 검사를 수행하거나 어설 션을 사용하는 경우 다음 요소를 고려합니다.

  1. 강력한 검증. 강력한 유효성 검사는 사용자 지정 예외를 발생시키는 것을 의미합니다 ( ApiError예 :) . 내 함수 / 메소드가 공개 API의 일부인 경우 예기치 않은 유형에 대한 좋은 오류 메시지를 표시하도록 인수의 유효성을 검사하는 것이 좋습니다. 유형을 확인하면을 사용하는 isinstance것이 아니라 전달 된 객체가 필요한 인터페이스를 지원하는 경우도 있습니다 (덕 타이핑). API를 문서화하고 예상되는 유형을 지정하고 사용자가 예기치 않은 방식으로 함수를 사용하려고 할 때 가정을 확인할 때 더 안전하다고 느낍니다. 나는 보통 사용 isinstance하고 나중에 다른 유형이나 오리를 지원하려면 유효성 검사 논리를 변경합니다.

  2. 독단적 프로그래밍. 내 코드가 새 코드이면 어설 션을 많이 사용합니다. 이것에 대한 당신의 조언은 무엇입니까? 나중에 코드에서 어설 션을 제거합니까?

  3. 내 함수 / 메소드가 API의 일부가 아니지만 일부 인수를 작성, 연구 또는 테스트하지 않은 다른 코드로 전달하면 호출 된 인터페이스에 따라 많은 주장을 수행합니다. 내 논리는 내 코드에서 더 잘 실패한 다음 이해할 수없는 오류로 인해 스택 추적에서 10 레벨 더 깊어집니다.

유형 / 값 유효성 검사를 언제 사용할 지에 대한 의견과 조언이 필요합니까? 질문을 가장 잘 작성하지 못해서 죄송합니다.

예를 들어 Customer, SQLAlchemy 선언 모델이있는 다음 함수를 고려하십시오 .

def add_customer(self, customer):
    """Save new customer into the database.
    @param customer: Customer instance, whose id is None
    @return: merged into global session customer
    """
    # no validation here at all
    # let's hope SQLAlchemy session will break if `customer` is not a model instance
    customer = self.session.add(customer)
    self.session.commit()
    return customer

따라서 유효성 검사를 처리하는 몇 가지 방법이 있습니다.

def add_customer(self, customer):
    # this is an API method, so let's validate the input
    if not isinstance(customer, Customer):
        raise ApiError('Invalid type')
    if customer.id is not None:
        raise ApiError('id should be None')

    customer = self.session.add(customer)
    self.session.commit()
    return customer

또는

def add_customer(self, customer):
    # this is an internal method, but i want to be sure
    # that it's a customer model instance
    assert isinstance(customer, Customer), 'Achtung!'
    assert customer.id is None

    customer = self.session.add(customer)
    self.session.commit()
    return customer

오리 타이핑, 유형 검사, 데이터 유효성 검사와 관련하여 이러한 요소를 언제, 왜 사용 하시겠습니까?


1
성능상의 이유가 아니라면 단위 테스트처럼 단언을 제거해서는 안됩니다.
Bryan Chen

답변:


4

몇 가지 지침 원리를 알려 드리겠습니다.

원칙 # 1. http://docs.python.org/2/reference/simple_stmts.html에 설명 된대로 어설 션의 성능 오버 헤드는 명령 줄 옵션으로 제거 할 수 있으며 여전히 디버깅을 위해 있습니다. 성능에 문제가 있으면 그렇게하십시오. 주장은 맡겨 (그러나 주장에 중요한 것은하지 마십시오!)

원칙 # 2. 무언가를 주장하고 있는데 치명적인 오류가 발생하면 어설 션을 사용하십시오. 다른 일을하는 데는 절대 가치가 없습니다. 나중에 누군가가 변경을 원하면 코드를 변경하거나 해당 메소드 호출을 피할 수 있습니다.

원칙 # 3. 어리석은 일이라고 생각하기 때문에 무언가를 허용하지 마십시오. 따라서 메서드가 문자열을 허용하면 어떻게됩니까? 작동하면 작동합니다.

원칙 # 4. 실수의 징후 인 것을 금지하십시오. 예를 들어 옵션 사전을 전달하는 것을 고려하십시오. 해당 사전에 유효한 옵션이 아닌 것들이 포함되어 있다면 누군가 API를 이해하지 못했거나 오타가 있음을 나타냅니다. 그것에 부는 것은 누군가가 합리적인 일을하지 못하게하는 것보다 오타를 잡을 가능성이 더 큽니다.

처음 두 가지 원칙에 따라 두 번째 버전을 버릴 수 있습니다. 당신이 선호하는 다른 두 가지는 맛의 문제입니다. 어느 쪽이 더 가능성이 있다고 생각합니까? 고객이 아닌 고객에게 전달하여 문제가 발생 add_customer하거나 (이 경우 버전 3이 선호 됨) 누군가가 고객을 올바른 모든 방법에 응답하는 일종의 프록시 객체로 교체하려고합니다. (이 경우 버전 1이 선호됩니다).

개인적으로 나는 두 가지 실패 모드를 보았다. 나는 게으르고 타이핑이 적다는 일반적인 원칙에서 버전 1을 사용하는 경향이 있습니다. (또한 이러한 종류의 실패는 대개 상당히 명백한 방식으로 조만간 나타납니다. 그리고 프록시 객체를 사용하려고 할 때 제 손을 묶은 사람들에게 정말로 화가납니다.) 다른 방향으로 갈 것입니다.


특히 인터페이스를 디자인 할 때 v.3을 선호합니다. 새로운 클래스와 메소드를 작성합니다. 또한 v.3은 API 메소드에 유용하다고 생각합니다. 내 코드는 다른 사람들에게 새롭기 때문입니다. 단정적 접근 방식은 최적화 모드에서 실행할 때 프로덕션 환경에서 제거되기 때문에 좋은 절충안이라고 생각합니다. > 그것으로 폭파하면 누군가가 합리적인 일을하지 못하게하는 것보다 오타를 잡을 가능성이 높습니다. <그래서, 당신은 그런 유효성 검사를 신경 쓰지 않습니까?
warvariuc

이런 식으로하자. 상속은 디자인을 어떻게 발전시키고 싶은지에 잘 맞지 않습니다. 나는 구성을 선호합니다. 그래서 나는 이것이 그 클래스에 속해야한다고 주장하는 것을 부끄러워했다. 그러나 나는 그들이 저를 무언가를 구한다고 생각하는 주장에 반대하지 않습니다.
btilly 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.