📙 Fundamentals/Python

Python_ 실습정리(1) : 클래스와 객체

Lento_ 2025. 3. 18. 18:12

[ 클래스와 객체 ]

1. 시간 추척 클래스

     - 메서드와 속성 이름 동일 에러발생

2. 직원 관리 시스템

     - 클래스 메서드 관련 메모

3. 프랜차이즈 레스토랑 예약 관리 시스템

     - 데이터 유효성

(시간 추적 클래스)

  • 실습 설명
    시간을 관리하고 추적하는 TimeTracker 클래스를 구현하는 프로젝트를 시작합니다. 시간 관리 기능은 특히 프로젝트 작업, 운동, 공부 시간 등 다양한 활동의 지속 시간을 측정하는 데 유용합니다.
    TimeTracker 클래스는 다음 기능을 제공해야 합니다:
    1. 시작 시간 설정: 사용자가 활동을 시작할 때의 시간을 기록합니다.
    2. 종료 시간 설정: 사용자가 활동을 종료할 때의 시간을 기록합니다.
    3. 경과 시간 계산: 활동의 시작과 종료 사이의 시간 차이를 계산합니다.
    이 클래스의 인스턴스를 사용하여 각각의 활동에 대해 별도의 시간 추적을 할 수 있어야 합니다.
  • 구현해야 할 메소드
    • start: 현재 시간을 시작 시간으로 설정합니다.
    • stop: 현재 시간을 종료 시간으로 설정하고 경과 시간을 계산합니다.
    • get_elapsed_time: 마지막으로 기록된 시작 시간과 종료 시간 사이의 경과 시간을 분 단위로 반환합니다.
  • 요구 사항
    1. 실제 시간을 추적하려면 Python의 datetime 모듈을 사용하여 현재 시간을 datetime.now()로 가져올 수 있습니다.
    2. 경과 시간은 분 단위로 반환해야 합니다.
#🚨에러 발생한 코드🚨
from datetime import datetime

class TimeTracker:
    def __init__(self):
        self.start = None
        self.stop = None

    def start(self):
        self.start = datetime.now()
        print("활동 시작 시간:", self.start)
        
    def stop(self):
        self.stop = datetime.now()
        print("활동 끝난 시간:", self.stop)
        
    def get_elapsed_time(self):
        self.get_elapsed_time= (self.stop - self.start).total_seconds() / 60
        return round(elapsed_time,1)

에러 문구: TypeError: 'NoneType' object is not callable

(에러 발생 이유)

: 메서드 이름과 속성 이름이 동일하기 때문이었다.

: 메서드와 속성의 이름이 동일할 경우, 속성이 메서드를 덮어쓰게 되어 메서드가 사라지면서 호출할 수 없게 된다. 그러므로 메서드와 속성의 이름은 동일하게 해서는 안된다.

# 에러 수정 후 코드
from datetime import datetime


class TimeTracker:
    def __init__(self):
        self.start_time = None
        self.stop_time = None

    def start(self):
        self.start_time = datetime.now()
        print("활동 시작 시간:", self.start_time)
        
    def stop(self):
        self.stop_time = datetime.now()
        print("활동 끝난 시간:", self.stop_time)
        
    def get_elapsed_time(self):
        self.elapsed_time= (self.stop_time - self.start_time).total_seconds() / 60
        return round(self.elapsed_time,1)

 

(직원 관리 시스템)

  • 실습 설명
    당신은 회사의 HR 부서에서 일하며, 회사 내 모든 직원의 급여 정보를 관리하는 시스템을 개발할 임무를 맡았습니다. 이 시스템은 직원들의 정보를 저장하고, 전체 직원의 평균 급여를 계산하는 기능을 제공해야 합니다.
    EmployeeManager 클래스는 다음 기능을 제공해야 합니다:
    • 직원 추가: 새로운 직원의 정보를 시스템에 추가합니다. 직원의 이름과 급여 정보를 저장합니다.
    • 급여 평균 계산: 클래스 메서드를 사용하여 모든 직원의 급여 평균을 계산합니다. 이 메서드는 저장된 모든 직원의 급여 정보를 집계하여 평균 급여를 계산하고 출력합니다.
  • 구현해야 할 메소드
    • __init__: 직원의 이름과 급여를 초기화하고, 직원 정보를 클래스 변수에 저장합니다.
    • calculate_average_salary: 클래스 메서드로 구현되며, EmployeeManager에 저장된 모든 직원의 급여 평균을 계산합니다.
  • 요구 사항
    • 직원 정보는 클래스 변수 employees에 저장되어 전체 EmployeeManager 인스턴스에서 접근 가능해야 합니다.
    • calculate_average_salary 메서드는 저장된 모든 직원의 급여를 합산하여 평균을 출력하고, 직원이 없는 경우 0을 반환해야 합니다.
class EmployeeManager:
    manage = []
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
        EmployeeManager.manage.append(self)
        print(f'{self.name} 님이 추가되었습니다. 급여: {self.salary}원')
    
    @classmethod
    def calculate_average_salary(cls):
        salaries = [manage.salary for manage in cls.manage]
        average = sum(salaries) / len(salaries)
        print(f'전체 직원의 평균 급여: {average}원')

(메모)

처음에 self.name을 키로 사용하여 딕셔너리로 작성했으나, 가독성이 떨어지는 문제를 발견했다. 그래서 리스트를 활용하여 재작성하였고, 객체에 속성을 추가하는 것에 있어서 더 용이하다는 점을 고려하여 리스트 사용이 적합하다고 판단했다.

⭐️클래스 매서드에서는 cls.manage로 접근한다.⭐️

→ 여기서 clsEmployeeManager 클래스 자체를 의미함.

 

(프랜차이즈 레스토랑 관리 클래스)

  • 실습 설명
    당신은 여러 지점을 가진 레스토랑 체인의 IT 팀에서 일하며, 각 지점의 예약을 관리하고 중앙에서 예약 현황을 파악할 수 있는 시스템을 개발할 임무를 맡았습니다. 이 시스템은 각 지점의 예약 상황을 관리하고, 고객의 예약 요청을 효과적으로 처리할 수 있는 기능을 제공해야 합니다.
    ReservationSystem 클래스는 각 레스토랑 지점의 예약을 관리하며, 다음 기능을 제공해야 합니다:
    • 예약 추가: 고객이 특정 지점, 예약 일시, 인원 수에 대한 예약을 요청하면 시스템에 추가합니다.
    • 예약 취소: 고객이 예약을 취소할 수 있으며, 해당 예약을 시스템에서 제거합니다.
    • 예약 조회: 특정 지점의 모든 예약 상황을 확인할 수 있습니다.
    • 예약 집계: 모든 지점의 예약 수를 합산합니다. 이 메서드는 모든 ReservationSystem 인스턴스의 예약 수를 합산하여 보여줍니다.
  • 구현해야 할 메소드
    • __init__: 레스토랑 지점의 이름을 초기화하고 예약 리스트를 관리합니다.
    • add_reservation: 새로운 예약을 추가합니다. 이 메서드는 예약자 이름, 예약 일시, 인원 수를 받아 저장합니다.
    • list_reservations: 현재 지점의 모든 예약 상태를 출력합니다.
    • sum_reservations: 주어진 ReservationSystem 인스턴스 리스트에서 모든 예약 수를 합산합니다.
  • 요구 사항
    • 모든 출력 메시지는 한국어로 제공되어야 합니다.
    • 각 메서드는 적절한 입력 검증과 예외 처리를 포함해야 합니다.
    • sum_reservations 클래스 메서드는 모든 지점에서의 예약 수를 효과적으로 합산하여 전체 예약 상태를 중앙에서 확인할 수 있게 합니다.
import re
class ReservationSystem:
    def __init__(self, store):
        self.store = store
        self.reservations = []

    def add_reservation(self, name, date, people):
        if not isinstance(name, str) or not name.strip():
            raise ValueError("예약자 성함이 비어있거나 문자열 형태가 아닙니다. 다시 입력해주세요.")

        if not isinstance(date, str) or not re.match(r"\d{4}-\d{2}-\d{2}", date) or not date.strip():
            raise ValueError("날짜는 YYYY-MM-DD 형태로 입력해주세요.")

        if not isinstance(people, int) or people <= 0:
            raise ValueError("인원 수는 숫자로 입력해주세요. 예약은 1명 이상부터 가능합니다.")

        reservation = {'이름' : name , '날짜' : date, '인원' : people}
        self.reservations.append(reservation)

    def list_reservations(self):
        #현 지점의 모든 예약 상태 출력
        print(f"{self.store} 예약 목록: ")
        for i in self.reservations:
            print(f"- {i['이름']}, {i['날짜']}, {i['인원']}명")

    def cancel_reservation(self, name, date):
        for i in self.reservations:
            if i['이름']==name and i['날짜']==date:
                self.reservations.remove(i)
                print(f'{name}님의 {date} 예약이 취소되었습니다.')

    @classmethod
    def sum_reservations(cls, stores):
        total = sum(len(k.reservations) for k in stores)
        return f"\n 전체 레스토랑 예약 수: {total}"

<데이터 유효성 검사> 

1. isinstance() 이용한 데이터 타입 검증

# 기본 사용법
isinstance(object, classinfo)

-  object : 타입을 확인하고자 하는 객체

-  classinfo : 객체가 속해야하는 데이터 타입 또는 클래스

-  반환값 = True / False

# 여러 개의 타입과 비교
# 튜플 사용

print(isinstance(10, (int, float)))   # True (10은 int, float 중 하나)
print(isinstance(10.5, (int, float))) # True (10.5는 float)
print(isinstance("hello", (int, float))) # False (문자열은 해당 안 됨)

☑️ 튜플을 활용하면 다양한 데이터 타입을 한 번에 검사할 수 있다.

 

(주의할 점) 

  • 상속 관계에서도 적용이 된다.

 

2. re.match()를 활용한 정규 표현식 데이터 검증

: 정규 표현식(Regular Expressions, regex)은 문자열이 특정 패턴을 따르는지 확인할 때 사용한다.

: ex) 날짜, 이메일, 전화번호, 비밀번호 등의 형식

 

"re.match()"

# 기본 사용법
import re
re.match(정규표현식, 문자열)

-  문자열이 특정 패턴으로 시작하는지 검사하는 함수(문자열의 앞 부분)

-  반환값 : match 객체 반환(패턴이 문자열 맨 앞에서 일치) / None 반환(불일치)

 

+) re.match()  VS  re.search()

함수 기능 차이점
re.match() 문자열 처음부터 검사 처음부터 일치해야 함
re.search() 문자열 전체에서 검사 중간에 포함되어도 일치

 

 

3. raise ValueError

: 잘못된 입력 방지를 위한 예외 처리

: 데이터 형식은 맞지만, 값이 잘못되었을 때 사용

: ValueError = 함수나 연산이 예상한 타입은 맞지만, 값이 적절하지 않을 때 발생하는 오류

# 기본 사용법
raise ValueError("오류 메시지")

 

"raise ValueError와 try-except"

# try-except를 사용한 예외 처리
def get_positive_number(value):
    try:
        if value <= 0:
            raise ValueError("양수만 입력해야 합니다.")
        return f"입력된 값: {value}"
    except ValueError as e:
        return f"오류 발생: {e}"

print(get_positive_number(10))   # 정상
print(get_positive_number(-5))   # 오류 메시지 출력

---> 예외 발생 시 프로그램이 중단되지 않고, 사용자에게 오류 메시지를 제공

'📙 Fundamentals > Python' 카테고리의 다른 글

Numpy_04  (0) 2024.04.28
Numpy_03  (0) 2024.04.28
Note_Python_03  (0) 2024.04.27
Note_Python_02  (0) 2024.04.17
Numpy_02  (0) 2024.04.13