연습문제
연습문제 - 온라인 서점 시스템 구현하기
다음 문제들은 온라인 서점의 도서 관리 시스템을 구현하는 과제입니다.
도서 정보 관리, 전자책 기능, 할인 정책 등 실제 서점 운영에 필요한 다양한 기능을 배운 내용을 바탕으로 구현해보세요.
1번 문제
book_data = [
{
"isbn": "123-4-56-789012-3",
"title": "파이썬 클래스 톺아보기",
"author": "라이캣",
"price": 25000,
"stock": 10
},
{
"isbn": "123-4-56-789012-4",
"title": "JavaScript 베이스캠프",
"author": "빙키",
"price": 15000,
"stock": 5
}
]
book_data = [
{
"isbn": "123-4-56-789012-3",
"title": "파이썬 클래스 톺아보기",
"author": "라이캣",
"price": 25000,
"stock": 10
},
{
"isbn": "123-4-56-789012-4",
"title": "JavaScript 베이스캠프",
"author": "빙키",
"price": 15000,
"stock": 5
}
]
위 도서 데이터를 참고하여 Book 클래스를 만들어주세요.
- ISBN(국제표준도서정보)은 private 속성으로 설정
- price와 stock은 property를 사용하여 음수가 되지 않도록 구현
- 매직메서드 str, eq(isbn 기준), lt(가격 기준) 구현
다음 테스트 코드가 동작해야 합니다.
book1 = Book("123-4-56-789012-3", "파이썬 클래스 톺아보기", "라이캣", 25000, 10)
book2 = Book("123-4-56-789012-4", "JavaScript 베이스캠프", "빙키", 15000, 5)
print(book1.price) # 25000
book1.price = -5000 # 음수 price 설정 시도(에러발생)
print(book1.price) # 25000 (음수가 되지 않음)
print(book1.stock) # 10
book1.stock = -3 # 음수 stock 설정 시도(에러발생)
print(book1.stock) # 10 (음수가 되지 않음)
print(book1) # <파이썬 클래스 톺아보기> 저자: 라이캣, 가격: 25000원, 재고: 10권
print(book1 == book2) # False
print(book1 < book2) # False
book1 = Book("123-4-56-789012-3", "파이썬 클래스 톺아보기", "라이캣", 25000, 10)
book2 = Book("123-4-56-789012-4", "JavaScript 베이스캠프", "빙키", 15000, 5)
print(book1.price) # 25000
book1.price = -5000 # 음수 price 설정 시도(에러발생)
print(book1.price) # 25000 (음수가 되지 않음)
print(book1.stock) # 10
book1.stock = -3 # 음수 stock 설정 시도(에러발생)
print(book1.stock) # 10 (음수가 되지 않음)
print(book1) # <파이썬 클래스 톺아보기> 저자: 라이캣, 가격: 25000원, 재고: 10권
print(book1 == book2) # False
print(book1 < book2) # False
2번 문제
다음 추상 클래스와 Enum을 활용하여 도서관리 시스템을 구현하세요.
from abc import ABC, abstractmethod
from enum import Enum
class BookFormat(Enum):
PAPER = "종이책"
EBOOK = "전자책"
AUDIO = "오디오북"
from abc import ABC, abstractmethod
from enum import Enum
class BookFormat(Enum):
PAPER = "종이책"
EBOOK = "전자책"
AUDIO = "오디오북"
- Book을 추상 클래스로 변경하고, calculate_discount() 추상 메서드를 포함하도록 수정하세요.
- 각 도서 형식별로 할인율을 다르게 적용하세요.
- 종이책: 10% 할인
- 전자책: 20% 할인
- 오디오북: 15% 할인
다음 테스트 코드가 동작해야 합니다.
paper_book = PaperBook("123-4-56-789012-3", "파이썬 클래스 톺아보기", "라이캣", 25000, 10)
ebook = EBook("123-4-56-789012-4", "JavaScript 베이스캠프", "빙키", 15000, 5)
audio_book = AudioBook("123-4-56-789012-5", "Python 베이스캠프", "뮤라", 12000, 50)
print(paper_book.calculate_discount()) # 22500 (10% 할인)
print(ebook.calculate_discount()) # 12000 (20% 할인)
print(audio_book.calculate_discount()) # 10200 (15% 할인)
paper_book = PaperBook("123-4-56-789012-3", "파이썬 클래스 톺아보기", "라이캣", 25000, 10)
ebook = EBook("123-4-56-789012-4", "JavaScript 베이스캠프", "빙키", 15000, 5)
audio_book = AudioBook("123-4-56-789012-5", "Python 베이스캠프", "뮤라", 12000, 50)
print(paper_book.calculate_discount()) # 22500 (10% 할인)
print(ebook.calculate_discount()) # 12000 (20% 할인)
print(audio_book.calculate_discount()) # 10200 (15% 할인)
3번 문제
다음 데이터클래스를 상속받아 도서 클래스를 구현하세요.
from dataclasses import dataclass
@dataclass
class BookInfo:
title: str
author: str
publisher: str
from dataclasses import dataclass
@dataclass
class BookInfo:
title: str
author: str
publisher: str
각 클래스는 다음 특성을 가져야 합니다.
- PhysicalBook: weight(무게), size(크기) 추가
- EBook: format_type(파일형식), download_url(다운로드 URL) 추가
다음 테스트 코드가 동작해야 합니다.
physical_book = PhysicalBook(
title="파이썬 클래스 톺아보기",
author="라이캣",
publisher="위니북스",
weight=0.780, # kg
size="188*240*35" # mm
)
digital_book = EBook(
title="JavaScript 베이스캠프",
author="빙키",
publisher="위니북스",
format_type="EPUB",
download_url="https://example.com/download"
)
print(physical_book.title) # 파이썬 클래스 톺아보기
print(physical_book.weight) # 0.780
print(physical_book.size) # 188*240*35
print(digital_book.title) # JavaScript 베이스캠프
print(digital_book.format_type) # EPUB
print(digital_book.download_url) # https://example.com/download
physical_book = PhysicalBook(
title="파이썬 클래스 톺아보기",
author="라이캣",
publisher="위니북스",
weight=0.780, # kg
size="188*240*35" # mm
)
digital_book = EBook(
title="JavaScript 베이스캠프",
author="빙키",
publisher="위니북스",
format_type="EPUB",
download_url="https://example.com/download"
)
print(physical_book.title) # 파이썬 클래스 톺아보기
print(physical_book.weight) # 0.780
print(physical_book.size) # 188*240*35
print(digital_book.title) # JavaScript 베이스캠프
print(digital_book.format_type) # EPUB
print(digital_book.download_url) # https://example.com/download
4번 문제
다음 두 클래스를 함께 상속받는 EBook 클래스를 구현하세요.
class Book:
def __init__(self, title, price):
self._title = title
self._price = price
self._purchased = False
def purchase(self):
if self._purchased:
return "이미 구매한 도서입니다."
self._purchased = True
return "구매가 완료되었습니다."
class Downloadable:
def __init__(self):
self._download_count = 0
self._max_downloads = 2
def download(self):
if not hasattr(self, '_purchased') or not self._purchased:
return "구매 후 다운로드 가능합니다."
if self._download_count >= self._max_downloads:
return "다운로드 횟수를 초과했습니다."
self._download_count += 1
return f"다운로드 완료 (남은 횟수: {self._max_downloads - self._download_count})"
class Book:
def __init__(self, title, price):
self._title = title
self._price = price
self._purchased = False
def purchase(self):
if self._purchased:
return "이미 구매한 도서입니다."
self._purchased = True
return "구매가 완료되었습니다."
class Downloadable:
def __init__(self):
self._download_count = 0
self._max_downloads = 2
def download(self):
if not hasattr(self, '_purchased') or not self._purchased:
return "구매 후 다운로드 가능합니다."
if self._download_count >= self._max_downloads:
return "다운로드 횟수를 초과했습니다."
self._download_count += 1
return f"다운로드 완료 (남은 횟수: {self._max_downloads - self._download_count})"
EBook은 다음 특성을 가져야 합니다.
- Book과 Downloadable 다중 상속
- format_type(파일형식: EPUB/PDF) 속성 추가
- 가격이 20000원 이상인 경우 최대 다운로드 횟수 3회로 증가
- PDF 형식의 경우 가격 10% 할증
다음 테스트 코드가 동작해야 합니다.
ebook = EBook("파이썬 기초", 25000, "PDF")
print(ebook.purchase()) # "구매가 완료되었습니다."
print(ebook.download()) # "다운로드 완료 (남은 횟수: 2)"
print(ebook.download()) # "다운로드 완료 (남은 횟수: 1)"
print(ebook._price) # 27500
ebook = EBook("파이썬 기초", 25000, "PDF")
print(ebook.purchase()) # "구매가 완료되었습니다."
print(ebook.download()) # "다운로드 완료 (남은 횟수: 2)"
print(ebook.download()) # "다운로드 완료 (남은 횟수: 1)"
print(ebook._price) # 27500
5번 문제
다음 클래스의 메서드들을 구현하세요.
class Book(ABC):
_total_books = 0
_daily_sales = {} # 날짜별 판매량 기록
class Book(ABC):
_total_books = 0
_daily_sales = {} # 날짜별 판매량 기록
1. 클래스 메서드
- total_books(): 전체 도서 수 반환
- get_sales_by_date(date): 특정 날짜의 총 판매량 반환
- record_sale(date): 판매 기록 추가
- get_best_selling_date(): 가장 판매량이 많았던 날짜 반환
2. 정적 메서드
- calculate_bulk_discount(quantity): 대량 구매 시 할인율 계산
- 100권 이상: 20% 할인
- 50권 이상: 15% 할인
- 20권 이상: 10% 할인
- validate_isbn(isbn): ISBN 유효성 검사 (13자리가 맞는지, 숫자로만 이루어져 있는지 검사해야 합니다.)
- is_workday(date): 영업일 여부 확인 (주말, 공휴일은 제외합니다.)
다음 테스트 코드가 동작해야 합니다.
book = Book("123-4-56-789012-3", "파이썬 클래스 톺아보기", "라이캣", 25000, 10)
# 영업일 확인
print(Book.is_workday("2025-02-09")) # False (일요일)
print(Book.is_workday("2025-02-10")) # True (월요일)
# 판매 기록 추가
print(Book.record_sale("2025-02-09")) # "영업일이 아닙니다."
print(Book.record_sale("2025-02-10")) # "판매 기록이 추가되었습니다."
print(Book.record_sale("2025-02-10")) # "판매 기록이 추가되었습니다."
# 판매량 확인
print(Book.get_sales_by_date("2025-02-10")) # 2
print(Book.get_best_selling_date()) # "2025-02-10"
# 대량 구매 할인율
print(Book.calculate_bulk_discount(100)) # 0.2
print(Book.calculate_bulk_discount(30)) # 0.1
book = Book("123-4-56-789012-3", "파이썬 클래스 톺아보기", "라이캣", 25000, 10)
# 영업일 확인
print(Book.is_workday("2025-02-09")) # False (일요일)
print(Book.is_workday("2025-02-10")) # True (월요일)
# 판매 기록 추가
print(Book.record_sale("2025-02-09")) # "영업일이 아닙니다."
print(Book.record_sale("2025-02-10")) # "판매 기록이 추가되었습니다."
print(Book.record_sale("2025-02-10")) # "판매 기록이 추가되었습니다."
# 판매량 확인
print(Book.get_sales_by_date("2025-02-10")) # 2
print(Book.get_best_selling_date()) # "2025-02-10"
# 대량 구매 할인율
print(Book.calculate_bulk_discount(100)) # 0.2
print(Book.calculate_bulk_discount(30)) # 0.1
답안
class Book:
def __init__(self, isbn, title, author, price, stock):
self._isbn = isbn
self.title = title
self.author = author
self._price = price
self._stock = stock
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("가격은 음수가 될 수 없습니다.")
self._price = value
@property
def stock(self):
return self._stock
@stock.setter
def stock(self, value):
if value < 0:
raise ValueError("재고는 음수가 될 수 없습니다.")
self._stock = value
def __str__(self):
return f"<{self.title}> 저자: {self.author}, 가격: {self.price}원, 재고: {self.stock}권"
def __eq__(self, other):
if isinstance(other, Book):
return self._isbn == other._isbn
return False
def __lt__(self, other):
if isinstance(other, Book):
return self.price < other.price
return NotImplemented
# 사용 예시
books = [Book(**data) for data in book_data]
class Book:
def __init__(self, isbn, title, author, price, stock):
self._isbn = isbn
self.title = title
self.author = author
self._price = price
self._stock = stock
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("가격은 음수가 될 수 없습니다.")
self._price = value
@property
def stock(self):
return self._stock
@stock.setter
def stock(self, value):
if value < 0:
raise ValueError("재고는 음수가 될 수 없습니다.")
self._stock = value
def __str__(self):
return f"<{self.title}> 저자: {self.author}, 가격: {self.price}원, 재고: {self.stock}권"
def __eq__(self, other):
if isinstance(other, Book):
return self._isbn == other._isbn
return False
def __lt__(self, other):
if isinstance(other, Book):
return self.price < other.price
return NotImplemented
# 사용 예시
books = [Book(**data) for data in book_data]
from abc import ABC, abstractmethod
from enum import Enum
class BookFormat(Enum):
PAPER = "종이책"
EBOOK = "전자책"
AUDIO = "오디오북"
def get_discount_rate(self):
discount_rates = {
BookFormat.PAPER: 0.1,
BookFormat.EBOOK: 0.2,
BookFormat.AUDIO: 0.15
}
return discount_rates[self]
class Book(ABC):
def __init__(self, isbn, title, author, price, stock, format_type: BookFormat):
self._isbn = isbn
self.title = title
self.author = author
self.price = price
self.stock = stock
self.format_type = format_type
def calculate_discount(self):
return int(self.price * (1-self.format_type.get_discount_rate()))
class PaperBook(Book):
def __init__(self, isbn, title, author, price, stock):
super().__init__(isbn, title, author, price, stock, BookFormat.PAPER)
class EBook(Book):
def __init__(self, isbn, title, author, price, stock):
super().__init__(isbn, title, author, price, stock, BookFormat.EBOOK)
class AudioBook(Book):
def __init__(self, isbn, title, author, price, stock):
super().__init__(isbn, title, author, price, stock, BookFormat.AUDIO)
from abc import ABC, abstractmethod
from enum import Enum
class BookFormat(Enum):
PAPER = "종이책"
EBOOK = "전자책"
AUDIO = "오디오북"
def get_discount_rate(self):
discount_rates = {
BookFormat.PAPER: 0.1,
BookFormat.EBOOK: 0.2,
BookFormat.AUDIO: 0.15
}
return discount_rates[self]
class Book(ABC):
def __init__(self, isbn, title, author, price, stock, format_type: BookFormat):
self._isbn = isbn
self.title = title
self.author = author
self.price = price
self.stock = stock
self.format_type = format_type
def calculate_discount(self):
return int(self.price * (1-self.format_type.get_discount_rate()))
class PaperBook(Book):
def __init__(self, isbn, title, author, price, stock):
super().__init__(isbn, title, author, price, stock, BookFormat.PAPER)
class EBook(Book):
def __init__(self, isbn, title, author, price, stock):
super().__init__(isbn, title, author, price, stock, BookFormat.EBOOK)
class AudioBook(Book):
def __init__(self, isbn, title, author, price, stock):
super().__init__(isbn, title, author, price, stock, BookFormat.AUDIO)
@dataclass
class PhysicalBook(BookInfo):
weight: float
size: tuple
@dataclass
class EBook(BookInfo):
format_type: str
download_url: str
@dataclass
class PhysicalBook(BookInfo):
weight: float
size: tuple
@dataclass
class EBook(BookInfo):
format_type: str
download_url: str
class EBook(Book, Downloadable):
def __init__(self, title, price, format_type):
# 부모 클래스 초기화
Book.__init__(self, title, price)
Downloadable.__init__(self)
self._format_type = format_type
# 가격이 20000원 이상이면 다운로드 횟수 증가
if price >= 20000:
self._max_downloads = 3
# PDF 형식이면 가격 10% 할증
if format_type == "PDF":
self._price = int(self._price * 1.1)
@property
def format_type(self):
return self._format_type
@property
def price(self):
return self._price
class EBook(Book, Downloadable):
def __init__(self, title, price, format_type):
# 부모 클래스 초기화
Book.__init__(self, title, price)
Downloadable.__init__(self)
self._format_type = format_type
# 가격이 20000원 이상이면 다운로드 횟수 증가
if price >= 20000:
self._max_downloads = 3
# PDF 형식이면 가격 10% 할증
if format_type == "PDF":
self._price = int(self._price * 1.1)
@property
def format_type(self):
return self._format_type
@property
def price(self):
return self._price
from abc import ABC, abstractmethod
from datetime import datetime
class Book(ABC):
_total_books = 0
_daily_sales = {} # 날짜별 판매량 기록
def __init__(self, isbn, title, author, price, stock):
self._isbn = isbn
self.title = title
self.author = author
self.price = price
self.stock = stock
Book._total_books += 1
@classmethod
def total_books(cls):
"""전체 도서 수 반환"""
return cls._total_books
@classmethod
def get_sales_by_date(cls, date):
"""특정 날짜의 총 판매량을 반환"""
return cls._daily_sales.get(date, 0)
@classmethod
def record_sale(cls, date):
"""판매 기록"""
if not cls.is_workday(date):
return "영업일이 아닙니다."
cls._daily_sales[date] = cls._daily_sales.get(date, 0) + 1
return "판매 기록이 추가되었습니다."
@classmethod
def get_best_selling_date(cls):
"""가장 판매량이 많았던 날짜 반환"""
if not cls._daily_sales:
return None
return max(cls._daily_sales.items(), key=lambda x: x[1])[0]
@staticmethod
def calculate_bulk_discount(quantity):
"""대량 구매 시 할인율 계산"""
if quantity >= 100:
return 0.2
elif quantity >= 50:
return 0.15
elif quantity >= 20:
return 0.1
return 0
@staticmethod
def validate_isbn(isbn):
"""ISBN 유효성 검사"""
isbn = isbn.replace('-', '')
return isbn.isdigit() and len(isbn) == 13
@staticmethod
def is_workday(date_str):
"""영업일 여부 확인"""
try:
date = datetime.strptime(date_str, '%Y-%m-%d').date()
# 주말 체크
if date.weekday() >= 5: # 5는 토요일, 6은 일요일
return False
return True
except ValueError:
return False
from abc import ABC, abstractmethod
from datetime import datetime
class Book(ABC):
_total_books = 0
_daily_sales = {} # 날짜별 판매량 기록
def __init__(self, isbn, title, author, price, stock):
self._isbn = isbn
self.title = title
self.author = author
self.price = price
self.stock = stock
Book._total_books += 1
@classmethod
def total_books(cls):
"""전체 도서 수 반환"""
return cls._total_books
@classmethod
def get_sales_by_date(cls, date):
"""특정 날짜의 총 판매량을 반환"""
return cls._daily_sales.get(date, 0)
@classmethod
def record_sale(cls, date):
"""판매 기록"""
if not cls.is_workday(date):
return "영업일이 아닙니다."
cls._daily_sales[date] = cls._daily_sales.get(date, 0) + 1
return "판매 기록이 추가되었습니다."
@classmethod
def get_best_selling_date(cls):
"""가장 판매량이 많았던 날짜 반환"""
if not cls._daily_sales:
return None
return max(cls._daily_sales.items(), key=lambda x: x[1])[0]
@staticmethod
def calculate_bulk_discount(quantity):
"""대량 구매 시 할인율 계산"""
if quantity >= 100:
return 0.2
elif quantity >= 50:
return 0.15
elif quantity >= 20:
return 0.1
return 0
@staticmethod
def validate_isbn(isbn):
"""ISBN 유효성 검사"""
isbn = isbn.replace('-', '')
return isbn.isdigit() and len(isbn) == 13
@staticmethod
def is_workday(date_str):
"""영업일 여부 확인"""
try:
date = datetime.strptime(date_str, '%Y-%m-%d').date()
# 주말 체크
if date.weekday() >= 5: # 5는 토요일, 6은 일요일
return False
return True
except ValueError:
return False