programming코딩

Start Python #3 Backend Program 만들기 – Class

Python의 이용 범위가 워낙 넓어 어디서부터 시작해볼까 고민하다 그래도 제가 Python을 주로 사용하는 Backend Program을 만들어보려고 합니다. 오늘은 첫번째 단계로 Class 사용법에 대한 설명이 핵심입니다.

Python 3.4 이상 버전을 기준으로 합니다. 2.x로 했을때 Error 나는 부분이 있을 수 있습니다.

Program Design

Class Diagram

Database를 저장소로 Lotto 당첨번호를 CURD (Create, Update, Read, Delete) 하는 Program부터 시작해보겠습니다.

샘플 코드의 Class Diagram

폴더 구조 만들기

전 폴더 구조를 이렇게 만듭니다.

  • model – data model이나 Repository를 포함합니다.
  • tests – Chapter #2 Unit Test에서 이야기한 test 코드들이 위치합니다.
  • util – 다른 프로그램에서도 사용할 수 있는 코드들입니다. 나중에 이 파일들은 lib로 만들어서 python package site에 올려놓으면 편하게 사용이 가능합니다.

Program 만들기

Program은 앞서 붙인 Diagram을 바탕으로 만들겠습니다.

Python도 객체지향으로 개발할 때 생산성이 높아지는 경험을 하여 객체지향 개발을 강추합니다.

따라서 객체지향에서 필수인 Class를 먼저 짚고 넘어가겠습니다.

Class 정의

객체를 추상화 하여 객체를 만들 수 있도록 정의해주는 것입니다.

추상화는 객체에 대해서 속성을 정의하여 그 객체 자체는 아니지만 그 객체를 표현할 수 있도록 정의하는 과정을 말합니다.

Python에서 Class 적용하는 법

1. 기본 형태

Python Class 기본 형태

눈여겨 볼 부분은 다음과 같습니다.

  • : 로 마칩니다.
  • def __init__ 는 construction method입니다.
  • self는 현재 instance를 가르킵니다. 대신 생략하면 에러납니다. Class내 Method 정의할때에도 인자로 self를 넣어주어야 합니다. 메소드가 호출될때 자동으로 인자로 self가 전달됩니다.
  • self.dbname 은 class의 속성입니다. 여기서도 self를 사용해야 하는게 특징입니다.

2. 상속

Python Class 상속
  • 상속은 Class명 뒤에 () 에 상위 Class를 넣어줍니다.

3. Abstraction

Python Class Abstraction
  • 추상 베이스 클래스인 ABC를 상속받기 위해서 metaclass를 ABCMeta로 하여 상속받도록 합니다.

Python Class Encapsulation과 접근제어자

Class는 Encapsulation이 핵심입니다.

정보를 은닉하고 꼭 필요한 Interface만 제공하는 것입니다.

이를 제어하는 것이 접근 제어자입니다.

Python의 접근제어자는 Naming으로 결정합니다.

Source Code

앞에 그렸던 Diagram을 내용을 채우지 않고 그대로 만든 코드입니다.

앞서 언급한 3가지의 형태가 모두 있고 접근제어자도 적절하게 적용되어 있습니다.

util/__init__.py

from .DBConnection import DBConnection
from .DBModel import DBModel

util/DBConnection.py (기본 형태)

class DBConnection:
    dbname = ''
    def __init__(self, dbname):
        self.dbname = dbname

util/DBModel.py (Abstraction)

from abc import *

class DBModel(metaclass=ABCMeta):
    __dbConnection = None
    __tableName = None
    def __init__(self, dbConnection, tablename):
        self.__dbConnection = dbConnection
        self.__tableName = tablename

    def _query(self, sql):
        pass

    def __fetch(self):
        pass   

    def _commit(self):
        pass

    def _insert(self, values, columns):
        pass

    def _select(self, where):
        pass

    def _delete(self, where):
        pass

    def clear(self):
        pass

    def create(self, data):
        pass

    def update(self, data):
        pass

    def delete(self, data):
        pass

    def read(self, data):
        pass

aiLotto/model/__init__.py

from .Numbers import Numbers
from .WinNumbersRepository import WinNumbersRepository

aiLotto/model/Numbers.py (기본 형태)

class Numbers:
    uid = None
    nums = []
    nobonus = None

    def __init__(self, uid, nums, nobonus):
        self.uid = uid
        self.nums = nums
        self.nobonus = nobonus

    def verify(self):
        pass

aiLotto/model/WinNumbersRepository.py (상속)

import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))))

from util import DBModel

class WinNumbersRepository(DBModel):
    def __init__(self, dbConnection):
        super().__init__(dbConnection, 'win_numbers')

    def create(self, numbers):
        pass

    def read(self, round):
        pass

    def delete(self, round):
        pass

aiLotto/AiLottoApp.py (기본형태)

import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))

from util import DBConnection
from model import WinNumbersRepository

class AiLottoApp:
    __winNumbersRepository = None
    def __init__(self, dbname):
        dbConnection = DBConnection(dbname)
        dbConnection.connect()
        self.__winNumbersRepository = WinNumbersRepository(dbConnection)

마치며

위 미구현된 부분들을 이제 채워나갈 것입니다.

그전에 다른 폴더 import 하는 방법등을 해야 할것 같긴 합니다.

Thread Safe 싱글톤 패턴 내용과 이어지지는 않았지만 조만간 만나지 않을까 싶습니다.

Leave a Reply