Skip to Content
💻 코리아IT아카데미 신촌 - 프로그래밍 학습 자료

Topic 5: 클래스 고급 기능 - 더 강력한 객체 🚀

🎯 학습 목표

클래스 변수, 클래스 메서드, 특수 메서드 등 고급 기능을 활용하여 더욱 전문적이고 강력한 클래스를 설계할 수 있습니다.

🏢 클래스 변수 vs 인스턴스 변수

개념 이해

클래스 변수: 모든 객체가 공유하는 변수
인스턴스 변수: 각 객체가 개별적으로 가지는 변수

class Student: # 클래스 변수 - 모든 학생이 공유 school_name = "파이썬 고등학교" total_students = 0 def __init__(self, name, grade): # 인스턴스 변수 - 각 학생마다 다름 self.name = name self.grade = grade # 클래스 변수 수정 Student.total_students += 1 def introduce(self): print(f"{Student.school_name}{self.name}입니다!") # 학생들 생성 kim_cheolsu = Student("김철수", 2) lee_younghee = Student("이영희", 1) park_minsu = Student("박민수", 3) # 클래스 변수는 모든 객체가 공유 print(f"학교명: {Student.school_name}") print(f"총 학생 수: {Student.total_students}") kim_cheolsu.introduce() # 파이썬 고등학교의 김철수입니다! lee_younghee.introduce() # 파이썬 고등학교의 이영희입니다!

실용적인 예시: 은행 시스템

class BankAccount: # 클래스 변수 bank_name = "파이썬 은행" interest_rate = 0.03 # 연 이자율 3% total_accounts = 0 total_balance = 0 def __init__(self, owner, account_number, initial_balance=0): # 인스턴스 변수 self.owner = owner self.account_number = account_number self.balance = initial_balance # 클래스 변수 업데이트 BankAccount.total_accounts += 1 BankAccount.total_balance += initial_balance def deposit(self, amount): self.balance += amount BankAccount.total_balance += amount print(f"💰 {amount:,}원 입금 완료! 잔액: {self.balance:,}원") def withdraw(self, amount): if amount <= self.balance: self.balance -= amount BankAccount.total_balance -= amount print(f"💸 {amount:,}원 출금 완료! 잔액: {self.balance:,}원") else: print("잔액이 부족합니다!") def apply_interest(self): """이자 적용""" interest = int(self.balance * BankAccount.interest_rate) self.balance += interest BankAccount.total_balance += interest print(f"💎 이자 {interest:,}원 적용! 잔액: {self.balance:,}원") @staticmethod def get_bank_info(): """은행 전체 정보 조회""" print(f"=== {BankAccount.bank_name} 현황 ===") print(f"총 계좌 수: {BankAccount.total_accounts}개") print(f"총 예치금: {BankAccount.total_balance:,}원") print(f"현재 이자율: {BankAccount.interest_rate*100}%") # 은행 계좌들 생성 account1 = BankAccount("김철수", "123-456", 100000) account2 = BankAccount("이영희", "789-012", 500000) # 거래 진행 account1.deposit(50000) account2.withdraw(100000) # 이자 적용 account1.apply_interest() account2.apply_interest() # 은행 전체 현황 BankAccount.get_bank_info()

🏭 클래스 메서드 (@classmethod)

클래스 메서드의 특징

클래스 메서드는 cls 매개변수를 받아 클래스 자체에 접근할 수 있습니다.

class Car: total_cars = 0 fuel_types = ["가솔린", "디젤", "전기", "하이브리드"] def __init__(self, brand, model, fuel_type): self.brand = brand self.model = model self.fuel_type = fuel_type Car.total_cars += 1 @classmethod def get_total_cars(cls): """총 자동차 수 반환""" return cls.total_cars @classmethod def get_fuel_types(cls): """지원하는 연료 타입들 반환""" return cls.fuel_types @classmethod def create_electric_car(cls, brand, model): """전기차 생성 팩토리 메서드""" return cls(brand, model, "전기") @classmethod def change_fuel_policy(cls, new_types): """연료 정책 변경""" cls.fuel_types = new_types print(f"새로운 연료 정책: {new_types}") # 일반적인 자동차 생성 car1 = Car("현대", "소나타", "가솔린") car2 = Car("기아", "K5", "하이브리드") # 클래스 메서드로 전기차 생성 electric_car = Car.create_electric_car("테슬라", "Model 3") # 클래스 정보 조회 print(f"총 자동차 수: {Car.get_total_cars()}") print(f"연료 타입들: {Car.get_fuel_types()}") # 정책 변경 Car.change_fuel_policy(["전기", "수소", "하이브리드"])

⚙️ 정적 메서드 (@staticmethod)

유틸리티 함수로 활용

정적 메서드는 클래스나 인스턴스 상태에 접근하지 않는 독립적인 함수입니다.

class MathUtils: PI = 3.14159 @staticmethod def add(a, b): """덧셈""" return a + b @staticmethod def multiply(a, b): """곱셈""" return a * b @staticmethod def circle_area(radius): """원의 넓이 계산""" return MathUtils.PI * radius * radius @staticmethod def is_even(number): """짝수 판별""" return number % 2 == 0 @staticmethod def factorial(n): """팩토리얼 계산""" if n <= 1: return 1 return n * MathUtils.factorial(n - 1) # 정적 메서드 사용 (객체 생성 없이 사용 가능) print(f"5 + 3 = {MathUtils.add(5, 3)}") print(f"반지름 5인 원의 넓이: {MathUtils.circle_area(5)}") print(f"8이 짝수인가? {MathUtils.is_even(8)}") print(f"5! = {MathUtils.factorial(5)}")

실용적인 예시: 날짜 유틸리티

class DateUtils: @staticmethod def is_leap_year(year): """윤년 판별""" return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) @staticmethod def days_in_month(year, month): """해당 년월의 일수 반환""" days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] if month == 2 and DateUtils.is_leap_year(year): return 29 return days[month - 1] @staticmethod def format_date(year, month, day): """날짜 포맷팅""" return f"{year:04d}-{month:02d}-{day:02d}" @staticmethod def parse_date(date_string): """날짜 문자열 파싱""" parts = date_string.split('-') return int(parts[0]), int(parts[1]), int(parts[2]) # 날짜 유틸리티 사용 print(f"2024년은 윤년? {DateUtils.is_leap_year(2024)}") print(f"2024년 2월 일수: {DateUtils.days_in_month(2024, 2)}") print(f"포맷된 날짜: {DateUtils.format_date(2024, 3, 15)}") year, month, day = DateUtils.parse_date("2024-12-25") print(f"파싱 결과: {year}{month}{day}일")

✨ 특수 메서드 (Magic Methods)

str 메서드

객체를 문자열로 표현할 때 사용됩니다.

class Product: def __init__(self, name, price, category): self.name = name self.price = price self.category = category def __str__(self): """사용자 친화적인 문자열 표현""" return f"{self.name} - {self.price:,}원 ({self.category})" def __repr__(self): """개발자용 문자열 표현""" return f"Product('{self.name}', {self.price}, '{self.category}')" # 특수 메서드 사용 laptop = Product("게이밍 노트북", 1500000, "전자제품") print(str(laptop)) # __str__ 호출: 게이밍 노트북 - 1,500,000원 (전자제품) print(repr(laptop)) # __repr__ 호출: Product('게이밍 노트북', 1500000, '전자제품') print(laptop) # __str__ 호출 (기본)

len 메서드

len() 함수 호출 시 동작을 정의합니다.

class Playlist: def __init__(self, name): self.name = name self.songs = [] def add_song(self, song): self.songs.append(song) print(f"♪ '{song}' 추가됨") def __len__(self): """플레이리스트 곡 수 반환""" return len(self.songs) def __str__(self): return f"플레이리스트 '{self.name}' ({len(self)}곡)" # 플레이리스트 사용 my_playlist = Playlist("좋아하는 곡들") my_playlist.add_song("Dynamite") my_playlist.add_song("Permission to Dance") my_playlist.add_song("Butter") print(f"곡 수: {len(my_playlist)}") # __len__ 호출: 곡 수: 3 print(my_playlist) # 플레이리스트 '좋아하는 곡들' (3곡)

비교 특수 메서드

class Student: def __init__(self, name, score): self.name = name self.score = score def __eq__(self, other): """== 연산자""" return self.score == other.score def __lt__(self, other): """< 연산자""" return self.score < other.score def __le__(self, other): """<= 연산자""" return self.score <= other.score def __gt__(self, other): """> 연산자""" return self.score > other.score def __ge__(self, other): """>= 연산자""" return self.score >= other.score def __str__(self): return f"{self.name}({self.score}점)" # 학생들 비교 kim_cheolsu = Student("김철수", 85) lee_younghee = Student("이영희", 92) park_minsu = Student("박민수", 85) print(f"{kim_cheolsu} == {park_minsu}: {kim_cheolsu == park_minsu}") # True (같은 점수) print(f"{kim_cheolsu} < {lee_younghee}: {kim_cheolsu < lee_younghee}") # True (85 < 92) print(f"{lee_younghee} > {kim_cheolsu}: {lee_younghee > kim_cheolsu}") # True (92 > 85) # 리스트 정렬도 가능 students = [kim_cheolsu, lee_younghee, park_minsu] students.sort() # 점수 순으로 정렬 print("성적순 정렬:", [str(s) for s in students])

🎮 종합 예시: 게임 길드 시스템

class Guild: # 클래스 변수 total_guilds = 0 max_members = 50 def __init__(self, name, leader): self.name = name self.leader = leader self.members = [leader] self.level = 1 self.experience = 0 Guild.total_guilds += 1 def add_member(self, member_name): """길드원 추가""" if len(self.members) < Guild.max_members: self.members.append(member_name) print(f"✅ {member_name}님이 {self.name} 길드에 가입했습니다!") return True else: print(f"❌ 길드 정원이 가득참 (최대 {Guild.max_members}명)") return False def gain_experience(self, exp): """경험치 획득""" self.experience += exp print(f"🎯 길드 경험치 +{exp} (총 {self.experience})") # 레벨업 체크 while self.experience >= self.level * 1000: self.experience -= self.level * 1000 self.level += 1 print(f"🎉 길드 레벨업! Lv.{self.level}") @classmethod def get_guild_stats(cls): """전체 길드 통계""" print(f"=== 길드 현황 ===") print(f"총 길드 수: {cls.total_guilds}") print(f"길드 최대 인원: {cls.max_members}") @classmethod def change_max_members(cls, new_max): """최대 인원 정책 변경""" cls.max_members = new_max print(f"📋 길드 최대 인원이 {new_max}명으로 변경되었습니다!") @staticmethod def calculate_guild_power(level, member_count): """길드 전투력 계산""" return level * 100 + member_count * 50 def __len__(self): """길드원 수 반환""" return len(self.members) def __str__(self): power = Guild.calculate_guild_power(self.level, len(self.members)) return f"[{self.name}] Lv.{self.level} | 길드원: {len(self.members)}명 | 전투력: {power}" def __gt__(self, other): """길드 전투력 비교""" my_power = Guild.calculate_guild_power(self.level, len(self.members)) other_power = Guild.calculate_guild_power(other.level, len(other.members)) return my_power > other_power # 길드 시스템 사용 guild1 = Guild("드래곤슬레이어", "길드장김철수") guild2 = Guild("파이썬마스터", "마스터이영희") # 길드원 추가 guild1.add_member("전사박민수") guild1.add_member("마법사최지영") guild2.add_member("궁수정도윤") # 경험치 획득 guild1.gain_experience(800) guild1.gain_experience(500) # 레벨업! guild2.gain_experience(600) # 길드 정보 출력 print(f"\n{guild1}") print(f"{guild2}") # 길드 비교 if guild1 > guild2: print(f"\n🏆 {guild1.name}이 더 강력합니다!") else: print(f"\n🏆 {guild2.name}이 더 강력합니다!") # 전체 통계 Guild.get_guild_stats() # 정책 변경 Guild.change_max_members(100)

🚨 자주 발생하는 오류

오류 1: 클래스 변수와 인스턴스 변수 혼동

class Counter: count = 0 # 클래스 변수 def __init__(self): # ❌ 잘못된 접근 # count += 1 # NameError! # ✅ 올바른 접근 Counter.count += 1 # 또는 self.__class__.count += 1 def get_count(self): return Counter.count

오류 2: 특수 메서드 잘못 정의

class Student: def __init__(self, name, score): self.name = name self.score = score # ❌ 잘못된 특수 메서드 이름 # def __string__(self): # __str__이 맞음 # return self.name # ✅ 올바른 특수 메서드 def __str__(self): return f"{self.name}({self.score}점)"

💡 퀴즈: 클래스 고급 기능 이해도 체크

Q1. 클래스 변수의 특징은?

  1. 각 객체마다 다른 값을 가진다
  2. 모든 객체가 같은 값을 공유한다
  3. 객체를 생성해야 사용할 수 있다
  4. self로 접근해야 한다

💡 정답 확인

정답: 2번 (모든 객체가 같은 값을 공유한다)

클래스 변수는 클래스에 속하며 모든 인스턴스가 공유하는 변수입니다.

Q2. @staticmethod의 특징은?

  1. self 매개변수가 필요하다
  2. cls 매개변수가 필요하다
  3. 클래스나 인스턴스 없이도 호출 가능하다
  4. 인스턴스 변수에 접근할 수 있다

💡 정답 확인

정답: 3번 (클래스나 인스턴스 없이도 호출 가능하다)

정적 메서드는 독립적인 함수로, 클래스나 인스턴스 상태에 의존하지 않습니다.

Q3. str 메서드의 역할은?

  1. 문자열을 입력받는다
  2. 객체를 문자열로 표현한다
  3. 문자열의 길이를 반환한다
  4. 문자열을 비교한다

💡 정답 확인

정답: 2번 (객체를 문자열로 표현한다)

__str__ 메서드는 객체를 사용자 친화적인 문자열로 표현할 때 사용됩니다.

✅ 클래스 고급 기능 마스터 체크리스트

✅ 클래스 고급 기능 마스터 체크리스트

🌟 다음 단계 미리보기

클래스의 고급 기능을 익혔으니, 이제 클래스 간의 관계를 다뤄보겠습니다!

다음 토픽에서는:

  • 상속(Inheritance): 기존 클래스를 확장하기
  • 부모 클래스와 자식 클래스: 코드 재사용과 확장
  • 메서드 오버라이딩: 부모의 기능을 자식에 맞게 수정

예를 들어:

class Animal: # 부모 클래스 def __init__(self, name): self.name = name def speak(self): print(f"{self.name}가 소리를 냅니다") class Dog(Animal): # 자식 클래스 def speak(self): # 메서드 오버라이딩 print(f"{self.name}가 멍멍 짖습니다") class Cat(Animal): # 자식 클래스 def speak(self): # 메서드 오버라이딩 print(f"{self.name}가 야옹 웁니다") dog = Dog("뽀삐") cat = Cat("나비") dog.speak() # 뽀삐가 멍멍 짖습니다 cat.speak() # 나비가 야옹 웁니다

클래스가 다른 클래스를 기반으로 확장됩니다! 🌱

Last updated on