Backend/Python + FastAPI

Python Basics (2)

elevne 2022. 11. 23. 23:43

예외처리

 

Python도 다른 언어들과 마찬가지로 예외처리 구문을 사용할 수 있다. 아래와 같이 코드를 작성해줄 수 있다.

 

 

 

def readFile(fileName):
    try:
        f = open(fileName, "r")
    except:
        print("FILE OPEN ERROR")
    else:
        print(f.read)
        f.close()
    finally:
        print("DONE")

 

 

 

try 뒤의 구문을 try 하고, 실패할 시 except, 성공할 시 else 구문을 이어서 실행한다. finally 뒤의 구문은 마지막에 try 구문을 성공하든 실패하든 실행하게 된다. 파이썬의 else 구문에서는 try 구문에서 선언한 변수를 그대로 사용할 수 있기에 try 구문의 코드는 최소화하여 정말 예외가 필요한 코드만 작성하고 나머지는 변수로 저장하여 else 구문에서 처리하는 것이 효율적이라고 한다. (성능적인 차이가 꽤 크게 나타나는 것 같다.)

 

 

 

Decorator

 

Decorator은 말 그대로 장식을 하기 위한 문법이라고 한다. 기존의 Class, function을 수정하지 않고 기능을 덧붙일 수 있는 기능을 한다. Decorator pattern은 로직을 설계할 때 객체가 특정 작업을 추가할 수 있도록 코드를 작성하는 방법을 패턴화 시킨 것이다. 아래와 같이 간단하게 코드로 작성해볼 수 있다.

 

 

 

def deco(func):
    def wrapper():
        print("before")
        ret = func()
        print("after")
        return ret
    return wrapper

@deco
def base():
    print("MAIN FUNCTION")

if __name__ == "__main__":
    print("==DECORATOR==")
    base()

 

 

 

위 코드에서는 우선 중첩 함수인 deco를 선언한다. 이 함수는 Closure 형태로 wrapper(내부함수)를 반환하는 것을 확인할 수 있다. 그 후, base 함수를 선언할 때, 함수 위에 @deco를 적어주었는데 이것이 Python의 Decorator이다. 

 

 

Python에서 Decorator을 사용하기 위해서는 Class 혹은 function을 인자로 받는Closure을 정의하고 그 안에 기능을 구현하면 된다. 다음으로, Decorator을 사용하는 함수나 클래스의 선언 바로 윗줄에 @ 키워드를 사용해서 미리 선언해둔 Closure 명을 적어주면 된다. 위 코드의 결과를 확인해보면 아래와 같다.

 

 

 

@deco

 

 

 

위 코드에서는 Python 파일이 실행될 때, base 함수가 실행되도록 작성되어 있다. base 함수는 단순히 "MAIN FUNCTION" 구문을 출력하기만 하는 함수이다. 하지만, 실행결과를 보면 그 전과 이후에 before, after이 순서대로 출력된 것을 확인할 수 있다. 여기서 출력된 두 문구는 Decorator로 사용된 deco 함수의 내부 함수인 Wrapper 함수에 정의된 것이다. Decorator은 함수나 클래스를 인자로 받는다. 그리고 인자로 받은 함수나 클래스를 실행하기 전이나 실행한 후 원하는 기능을 추가해줄 수 있는 것이다. 

 

 

 

그럼 Decorator을 어떠한 상황에 사용할 수 있을까? 일례로 한 함수의 실행시간을 측정하는데 사용할 수 있을 것이다. 아래와 같이 코드를 작성할 수 있을 것이다.

 

 

 

import time

def measure_run_time(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print("{} FUNCTION RUNNING TIME: {}".format(func.__name__, end-start))
        return result
    return wrapper

@measure_run_time
def exampleFunc(delay_time):
    time.sleep(delay_time)

if __name__ == "__main__":
    exampleFunc(3)

 

 

@measure_run_time

 

 

 

위처럼 Decorator을 적용한 함수의 실행시간을 확인할 수 있을 것이다. 다음 시간에는 이어서 다중 Decorator, Class Decorator의 사용법에 대해서 알아볼 예정이다.