[Python] 모듈화 ( 중급 예제 첨부 )

Seongkeun·2023년 3월 2일
1

Python

목록 보기
8/8
post-thumbnail

모듈화를 이해하기에 앞서 패키징을 이해하고 오면 모듈화에 대한 이해도를 더 높일 수 있습니다.
패키징이란?

사용 난이도 : 중

일단 따라치고 이해하면 편하다

사용환경

  • Ubuntu 22.04 LTS
  • Python 3.11
  • MySQL | sqlite3
    • MySQL 예시도 포함 되어있으나 이 글에서는 파이썬에서 제공하는 임시데이터베이스인 sqlite3 패키지를 주로 다룸
  • Docker (Docker 가 아니라도 무방함)

사용 패키지

  • setuptools, dotenv, mysql-connector-python
python3 -m pip install setuptools python-dotenv mysql-connector-python

파이썬 모듈화의 이해

파이썬에서 모듈은 함수나 변수, 클래스들을 담은 파일을 의미한다. 모듈을 활용하면 코드를 더욱 모듈화하고, 코드 재사용성을 높일 수 있어 유지보수성과 가독성을 향상시킬 수 있다.

Module Directory Structure

아래의 Directory 구조는 아래 보여줄 코드를 기반으로 함

../python_workspace/example_fibo/
├── setup.py
└── fibonacci_package/
    ├── __init__.py
    └── data_handler.py
    └── fibonacci_runner.py
    └── mysql_config.py
    └── mysql_data_repository.py

~/env_example/.env

setup.py

패키지를 빌드하고 설치하는데 사용

from setuptools import setup, find_packages

setup(
    name='fibonacci',
    version='1.0',
    description='이 것은 피보나치 예제입니다',
    author='seongkeun',
    author_email='osk3856@gmai.com',
    packages=find_packages(),
    install_requires=[
        'mysql-connector-python',
        'python-dotenv'
    ]
)


__init__.py

패키지의 초기화 파일

from .fibonacci_runner import run_fibonacci

__all__ = ['run_fibonacci']

data_handler.py

메인과 repository 의 연결지점. 데이터를 핸들링하는 파일

from .mysql_data_repository import MysqlDataRepository

class DataHandler:
  def __init__(self, start_date, end_date, user, password, host, port, database):
    self.start_date = start_date
    self.end_date = end_date
    self.mysql_repo = MysqlDataRepository(
        start_date = start_date,
        end_date = end_date,
        user = user,
        password = password,
        host = host,
        port = port,
        database = database
    )
    
  def put_data(self, date, data):
    return self.mysql_repo.put_data(date, data)

  def extract_data(self) :
    return self.mysql_repo.get_data()
  
  def fibonacci_tail(self, n, a=0, b=1):
    if n == 0:
        return a
    elif n == 1:
        return b
    else:
        return self.fibonacci_tail(n-1, b, int(a)+int(b))
  
  def calc_fibo(self, data_list) :  
    result = []

    for date, num in data_list:
      result.append(self.fibonacci_tail(num))
    return result

fibonacci_runner.py

메인이 될 파일이다

from .mysql_config import MysqlConfig
from .data_handler import DataHandler

def run_fibonacci(start_date=None, end_date=None, date=None, data=None):
  mysql_config=MysqlConfig.get_mysql_config(start_date, end_date)
  dh = DataHandler(
    start_date = mysql_config.start_date,
    end_date = mysql_config.end_date,
    user = mysql_config.user,
    password = mysql_config.password,
    host = mysql_config.host,
    port = mysql_config.port,
    database = mysql_config.database
  )
  
  for d, dt in zip(date, data):
    dh.put_data(d, dt)
  
  data_list = dh.extract_data()
  fibonacci_list = dh.calc_fibo(data_list)
  
  return fibonacci_list

mysql_config.py

이 파일은 MySQL Connection 에 필요한 파일입니다
사실상 이 글에 필요없는 코드이지만 나중을 위해 이해정도만 해주세요.

from dotenv import load_dotenv
import os
import re


class MysqlConfig:
  def __init__(self, start_date, end_date, user, password, host, port, database):
    self.start_date = start_date
    self.end_date = end_date
    self.user = user
    self.password = password
    self.host = host
    self.port = port
    self.database = database

  @classmethod
  def get_mysql_config(cls, start_date, end_date):
     
    load_dotenv(dotenv_path="/env_example/.env")
    database_url=os.getenv("DATABASE_INFO")
    database_array = re.split('\W+', database_url)

    user = database_array[1]
    password = database_array[2]
    host = database_array[3]
    port = database_array[4]
    database = database_array[5]
    
    return cls(
      start_date=start_date,
      end_date=end_date,
      user=user,
      password=password,
      host=host,
      port=port,
      database=database
    )

위 코드를 만들기 전에 ~/env_example/ 디렉토리에 .env 파일을 만들고 아래 url 형식으로 본인의 database 정보로 변경해서 넣어주세요

DATABASE_INFO=mysql://root:password@localhost:3306/flower
  • mysql : 어떤 DATABASE 를 사용하는지
  • root : user
  • password : password
  • localhost : host
  • 3306 : port
  • flower : database 이름

mysql_data_repository.py

원래는 MySQL 로 다루려고 했으나 sqlite3 라는 파이썬 임시데이터베이스로 처리 밑에 데이터베이스 Connect 하는 코드도 첨부함

import sqlite3

class MysqlDataRepository:
  def __init__(self, start_date, end_date, user, password, host, port, database):
      self.start_date = start_date
      self.end_date = end_date
      
      # SQLite 데이터베이스 연결
      self.conn = sqlite3.connect('fibonacci_example.db')
      self.cursor = self.conn.cursor()

      # fibonacci 테이블이 존재하지 않는 경우에만 생성
      self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='fibonacci';")
      result = self.cursor.fetchone()
      if not result:
          self.cursor.execute('''CREATE TABLE fibonacci
                  (date date, data INT)''')
          self.conn.commit()


  def close_mysql_connection(self) :
    self.cursor.close()
    self.conn.close()

  def put_data(self, date, data) :
    # 데이터 삽입
    self.cursor.execute(f"INSERT INTO fibonacci VALUES ('{date}', '{data}')")
    self.conn.commit()
    return True
    
  def get_data(self) :
    self.cursor.execute(f"SELECT *\
          FROM fibonacci\
          WHERE date BETWEEN '{self.start_date}' AND '{self.end_date}'")
    result = self.cursor.fetchall()
    self.close_mysql_connection()
    return result

번외 - MySQL Connect 하는 코드

아래 코드는 이 글에서 사용되지 않는 코드입니다. MySQL에 어떻게 Connection 하는 것인지 보여만 드리기 위해 첨부했습니다

import mysql.connector

class MysqlDataRepositoryOriginal:
  def __init__(self, start_date, end_date, user, password, host, port, database):
    self.start_date = start_date
    self.end_date = end_date
    self.conn = mysql.connector.connect(
      user=user,
      password=password,
      host=host,
      port=port,
      database=database
    )
    self.cursor = self.conn.cursor()

  def close_mysql_connection(self) :
    self.cursor.close()
    self.conn.close()

  def get_data(self) :
    self.cursor.execute(f"SELECT *\
          FROM table\
          WHERE date BETWEEN '{self.start_date}' AND '{self.end_date}'")
    result = self.cursor.fetchall()
    self.close_mysql_connection()
    return result

모듈화

1. python setup.py sdist

setup.py 가 있는 directory 를 터미널로 들아가서
python setup.py sdist 와 같이 친다
아래와 같이 마지막에 removing... 이 나오면 성공

파일이 위와 같이 만들어졌을겁니다
자물쇠 마크있는 것은 신경쓰지 않아도 됩니다.
저처럼 도커로 바운드 마운트 하고있는게 아니라면 저렇게 자물쇠 마크가 자동으로 생기지는 않을테니까요

2. 내 파이썬 모듈 설치 및 확인

Directory ./dist 에서 생성된 tar파일
(setup.py 를 저와 똑같이 따라쳤다면 fibonacci-1.0.tar.gz 생성됨) 을

fibonacci-1.0.tar.gz 를 설치하면 기본 패키지 저장소인 /usr/local/lib/python3.11/site-packages directory 에 저장이 됩니다.
(/lib 후에 있는 디렉토리명은 파이썬 버전마다 다르기에 lib 디렉토리 부터는 들어가서 확인하는 것을 추천)

2-1. (똑같이 따라하지 않으신 분들은 ls dist/ 로 dist 내부에 있는 .tar.gz 파일명 확인하세요)
pip install ./dist/fibonacci-1.0.tar.gz

위와 같이 나왔다면 모듈을 파이썬에서 사용할 수 있습니다.


하지만 만약 내가 원하는 저장소가 따로 있으면 아래와 같이 패키지 인스톨 하셔도 됩니다
(원하는 경로가 /dist-packages 라고 가정)

pip install ./dist/fibonacci-1.0.tar.gz --target=/usr/local/lib/python3.11/dist-packages

하지만 Python 이 패키지를 찾을 수 있게 패키지 경로가 추가 되어있어야 합니다. 패키지 경로 추가는 아래처럼 하시면 됩니다.
(local.pth 는 Python 패키지 경로 파일로 site-packages 의 하위 디렉토리로 추가시켜주는 파일입니다)

echo "/usr/local/lib/python3.11/dist-packages" | sudo tee -a /usr/local/lib/python3.11/site-packages/local.pth

2-2. pip list | grep "fibo" 를 입력하면 내 모듈이 저장된 것을 확인할 수 있습니다. 또한 pip show fibonacci 를 입력하면 설치경로 및 패키지에대한 정보를 얻을 수 있습니다.

2-3. /usr/local/lib/python3.11/site-packages 경로에서 ll | grep "fibo" OR ls | grep "fibo" 를 입력해보면 다음과 같은 패키지가 만들어져있는 것을 확인할 수 있습니다. .dist-info 는 말그대로 패키지에 대한 설명이고 우리가 필요한건 fibonacci_package 입니다. 파이썬에서 이 패키지 명으로 import 가 가능합니다

2-4. 이제 setup.py 파일이 존재하는 경로에 있는 /fibonacci.egg-info, /dist, fibonacci-1.0.tar.gz 는 삭제해도 됩니다.
단, 만약을 위해 setup.py/fibonacci_package 는 지우지 마세요

3. 파이썬 모듈 import 및 실행확인

자, 이제 거의 다 왔습니다. 본인이 사용하는 python 을 작업하는 디렉토리에서 이제 이 모듈을 불러와서 사용해볼 것입니다. 저는 그냥 setup.py 가 있던 디렉토리에 main.py 을 만들었습니다

main.py

from fibonacci_package import run_fibonacci
import json
import sys

date = ["2023-02-18", "2023-02-26", "2023-02-20", "2023-02-28", "2023-03-01", "2023-03-02"]
data = [7,11,5,9,15,3]

start_date="2023-02-22"
end_date="2023-03-01"

result = run_fibonacci(start_date=start_date, end_date=end_date, date=date, data=data)

# print(result) 도 가능하지만 sys.std 객체는 출력을 직접 제어할 수 있는 장점이 있습니다
json_data = json.dumps(result)
sys.stdout.write(json_data)

저는 jupyter lab 을 이용하기에 main.py 가 있는 디렉토리에서 터미널을 열어서 python3 -m main 을 입력해서 다음과 같이 결과를 확인했습니다. 커널이 연동되어있는 IDE 쓰시는 분들은 그냥 실행시켜서 확인해보면 될 것 같습니다.

이 패키지를 삭제하고싶으면 아무 디렉토리에서 pip uninstall fibonacci 를 입력하시면 됩니다

위 예시의 최종 디렉토리 구조는 다음과 같다

../python_workspace/example_fibo/
├── main.py
├── setup.py
└── fibonacci_package/
    ├── __init__.py
    └── data_handler.py
    └── fibonacci_runner.py
    └── mysql_config.py
    └── mysql_data_repository.py

~/env_example/.env

~/usr/local/lib/python3.11/site-packages/
├── fibonacci-1.0.dist-info/
├── fibonacci_package/
profile
지혜는 지식에서 비롯된다

0개의 댓글