[오늘의 배움] 034 파이썬 데코레이터, 플라스크 마이그레이션, SQLAlchemy ORM

이상민·2021년 1월 20일
0

[오늘의 배움]

목록 보기
37/70
post-thumbnail

1. 데코레이터

1-1. 클로저

def mul_of(m):
    def mul(n):
        return m * n
    return mul


if __name__ == "__main__":
    mul3 = mul_of(3)
    mul5 = mul_of(5)

    print(mul3(10))  # 30 출력
    print(mul5(10))  # 50 출력

파이썬에서 위 코드처럼 클래스를 이용한 것과 비슷하게 함수 안에 함수를 담아 반환하여 객체를 만드는 것을 클로저라고 한다.

1-2. 데코레이터

import time


def decorate(original_func):   # 기존 합수를 입력으로 받는다.
    def wrapper():
        start = time.time()
        original_func()    # 기존 함수를 수행한다.
        end = time.time()
        print("함수 수행시간: %f 초" % (end - start))
    return wrapper


def myfunc():
    """ 데코레이터 확인 함수 """
    print("함수가 실행됩니다.")


decorated_myfunc = decorate(myfunc)
decorated_myfunc()

파이썬에서 데코레이터란 기존 함수의 변경 없이 추가적인 기능을 덧붙일 수 있도록 해 주는 함수이다. 위 코드에선 기존 함수인 myfunc()를 decorate()함수에 인자로 주어 decorated_myfunc()이란 함수 실행 시간 기능을 추가한 함수를 만들었다. 공통된 추가 기능을 여러 함수에 추가하고자 할때 유용하다.

1-3. 어노테이션을 활용한 데코레이터

import time


def decorate(original_func):
    def wrapper():
        start = time.time()
        original_func()
        end = time.time()
        print("함수 수행시간: %f 초" % (end - start))
    return wrapper


@decorate
def myfunc():
    """ 데코레이터 확인 함수 """
    print("함수가 실행됩니다.")

# decorated_myfunc = decorate(myfunc)  # 데코레이터 어노테이션으로 인해 더이상 필요하지 않다.
# decorated_myfunc()
myfunc()

위 코드처럼 어노테이션을 이용해 더 가독성이 좋게 코드를 관리할 수 있다. 파이썬은 함수명 위의 어노테이션을 데코레이터 함수로 인식한다. 위에서 myfunc()은 decorate()를 거쳐서 수행된다. 이때 데코레이터 함수는 다양한 기존 함수에 대응할 수 있어야하기 때문에 wrapper 함수에 *args, **kwargs를 추가해 호출하도록 할 수 있다.

import time


def decorate(original_func):
    def wrapper(*args, **kwargs):   # *args, **kwargs 매개변수 추가
        start = time.time()
        original_func(*args, **kwargs)  # 전달받은 *args, **kwargs를 입력파라미터로 기존함수 수행
        end = time.time()
        print("함수 수행시간: %f 초" % (end - start))
    return wrapper


@decorate
def myfunc(msg):
    """ 데코레이터 확인 함수 """
    print("'%s'을 출력합니다." % msg)


myfunc("You need python")

1-4. @functools.wraps

import time
import functools


def decorate(original_func):
    @functools.wraps(original_func)
    def wrapper(*args, **kwargs):   # *args, **kwargs 입력인수 추가
        start = time.time()
        original_func(*args, **kwargs)  # 전달받은 *args, **kwargs를 입력파라미터로 기존함수 수행
        end = time.time()
        print("함수 수행시간: %f 초" % (end - start))
    return wrapper


@decorate
def myfunc(msg):
    """ 데코레이터 확인 함수 """
    print("'%s'을 출력합니다." % msg)

데코레이터 작성 시 위처럼 @functools.wraps()를 추가해줘야 함수의 올바른 동작을 보장할 수 있다.
https://wikidocs.net/83687


2. 데이터베이스 마이그레이션

= 스키마 마이그레이션 = 데이터베이스 변경 관리

2-1. 스키마 마이그레이션

데이터베이스 마이그레이션이란 관계 데이터베이스 스키마에 대해 점진적, 가역적 변경을 관리하는 것과 버전 관리하는 것을 의미한다. 데이터베이스 스키마를 새로운/이전 버전으로 업데이트/복구할때 스키마 마이그레이션을 수행한다. 스키마 마이그레이션 도구를 이용해 수행된다.
https://en.wikipedia.org/wiki/Schema_migration

2-2. Flask-Migrate

Alembic을 이용해 Flask 응용프로그램에 대해 SQLAlchemy 데이터베이스 마이그레이션을 관리하는 익스텐션이다.

Almebic이란 SQLAlchemy를 이용할때 사용할 수 있는 스키마 마이그레이션 도구이다.

예시)

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'

db = SQLAlchemy(app)
migrate = Migrate(app, db)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128))

위 응용프로그램을 갖고 아래 명령어로 마이그레이션 레포지토리를 생성할 수 있다. 이 레포지토리도 소프트웨어 버전 관리 시 추가해줘야한다.

$ flask db init

이후 마이그레이션을 생성할 수 있다. 데이터베이스 변경을 자동 감지해 리비전 스크립트를 작성하지만 모든 변경이 자동 감지 되지 않기 때문에 데이터베이스 적용전에 스크립트를 확인해줘야한다.

$ flask db migrate -m "migration message"

다음 명령어로 데이터베이스에 마이그레이션을 적용할 수 있다.

$ flask db upgrade

https://flask-migrate.readthedocs.io/en/latest/#example


3. SQLAlchemy ORM

파이썬에서 데이터베이스를 사용하기 위해 다양한 도구를 제공하는 SQLAlchemy를 자주 사용한다.

3-1. ORM

Object Relational Mapping

ORM이란 객체 지향 언어를 이용해 호환되지 않는 타입 시스템간 데이터를 변환하는 기술이다. 이 과정에서 가상의 객체 데이터베이스를 생성하게되어 프로그래밍 언어에서 사용 가능해진다.

3-2. SQLAlchemy ORM

SQLAlchemy를 이루는 도구 중 하나이다. 유저가 명시한 클래스를 데이터베이스 테이블과, 그 클래스의 객체를 테이블의 인스턴스를 연관 시켜준다. 이때 연관된 객체와 인스턴스의 상태 변화를 동기시켜주는 시스템과 유저가 명시한 클래스와 관계로 데이터베이스 쿼리를 표현하는 시스템을 포함한다.

https://docs.sqlalchemy.org/en/13/orm/index.html

profile
편하게 읽기 좋은 단위의 포스트를 추구하는 개발자입니다

0개의 댓글