대우를 활용한 코드 최적화(Optimize code with Contrapositive)

2024. 9. 9. 15:26학습/python

A이면 B이다. ~B이면 ~A이다.
If P, Then Q. If not Q, Then not P.

 

 

 

대우를 활용해서 파이썬에서 코드 최적화 방법에 대해 정리해본다.

1. 조건문 최적화

2. 예외 처리

3. 논리적 동치 != 복잡도

  - O(1) -> O(n) 되는 경우


 

1. 조건문 최적화

# 원래 조건문
if not (P and Q):
    do_something()

# 대우를 활용한 조건문
if not P or not Q:
    do_something()

 

not (P and Q) == not P or not Q 

드 모르간 법칙.

 

논리적으로는 동치지만 코드 최적화 부분에서는 느낌이지만 미세하게나마 차이가 존재한다.

 

  1.1 차이

  • 둘 다 모두 O(1) 이다.
  • 다만 전자의 경우 P가 False 일 경우에도 Q를 판단해야 한다.
  • 후자의 경우 P가 False 일 경우 즉시 전체 조건이 True 가 되어 Q를 판단하지 않아도 된다.
  • 단락 평가(short-circuit evaluation)

  1.2 기타

  • 가독성 은 취향차이라고 생각.
  • 후자를 사용해 쬐에에에끔이나마 최적화에 관심이 있다는것을 어필할 수 있음.

2. 예외 처리

def process_data(data):
    # 원래 조건
    if data is not None and len(data) > 0:
        # 데이터 처리
        pass
    else:
        raise ValueError("유효하지 않은 데이터임")

    # 대우를 활용한 조건
    if data is None or len(data) == 0:
        raise ValueError("유효하지 않은 데이터임")
    # 데이터 처리

 

 

  2.1 차이

  • 역시 둘다 모두 O(1).
  • 후자가 유효하지 않은 데이터를 더 빨리 감지할 수 있다.
    data is None이 True라면 len(data)를 확인하지 않고 바로 예외를 발생.
  • 빠른 실패(Fail-fast)의 구현

3. 논리적 동치 != 복잡도

# 원래 조건
if not (x < 0 or x > 100):
    print("0 과 100 사이에 있어!")

# 대우를 활용한 조건
if 0 <= x <= 100:
    print("0과 100 사이에 있어!")

 

억지춘향 느낌이 나는 예시.

1,2 번 예시와 비슷한 장점이 있음.

 

다만 공부하면서 논리적으로 동치지만 주의해야하는 점들이 몇몇 있었는데,

아래에 설명.

# 원래 조건
if not (s == "" or s == " "):
    print("s는 빈 문자열이 아님")

# 대우를 활용한 조건
if s.strip():  # strip() 메서드를 이용해 공백을 제거
    print("s는 빈 문자열이 아님")

 

 

if not (s == "" or s == " ")

 문자열 s가 빈 문자열이거나 공백 문자열일 때 False를 반환.

즉, s가 비어 있지 않거나 공백이 아닐 때 True를 반환함.

if s.strip():

 s의 양쪽 공백을 제거한 후, 그 결과가 비어 있지 않으면 True를 반환.

즉, s가 빈 문자열이거나 공백만 있을 경우 False를 반환.

 

두 조건문은 모두 문자열 s에 공백 이외의 문자가 존재하는 경우에 참이 되므로, 논리적으로 동치입니다..

즉, 두 조건문 중 어느 것을 사용해도 동일한 결과를 얻을 수 있다.

 

다만 복잡도에서 큰 차이가 있는데,

 

  3.1 시간 복잡도

    if not (s == "" or s == " ")

  • 문자열 비교 연산이 2번 수행됨.
  • O(1)

    if s.strip():

  • strip()은 문자열 전체를 한 번 스캔하여 양쪽 끝의 공백을 제거함.
  • O(n)

  3.2 공간 복잡도

   if not (s == "" or s == " ")

  • O(1)

    if s.strip():

  • 원본 문자열을 수정하지 않고 새로운 문자열을 생성.
  • 최악의 경우, 원본 문자열과 동일한 크기의 새로운 문자열이 생성될 수 있음.
  • O(n)

시간과 공간 복잡도 모두 O(1)이 O(n)으로 증가하는 대참사가 발생한다...

항상 메서드나 함수를 사용할 때 주의해야하는 점이다...


 

728x90