멀티캠퍼스 데이터분석 4월 10일 수업 내용 정리입니다.
이론
1. 클래스란?
2. 클래스 구성
3. 클래스 선언
4. 생성자 __init__ & self
5. 클래스 변수
6. 상속
실습
*args)→ 클래스는 무언가를 똑같이 만들어주는 설계도와 같은 의미입니다.
클래스는 크게 2가지로 구성됩니다.
| 구성 요소 | 설명 |
|---|---|
| 속성 (Attribute) | 클래스가 가지는 변수 |
| 메서드 (Method) | 클래스가 가지는 동작(함수) |
파이썬에서 클래스를 선언하는 방식은 class 키워드와 클래스 이름을 나열하여 선언합니다.
class 클래스이름:
pass
💡 클래스 이름은 관례적으로 첫 글자를 대문자로 표기합니다. (PascalCase)
__init__ & self__init__ : 클래스를 생성 시 초기화하며 자동 실행되는 함수self : 객체 자기 자신을 참조하는 매개변수__init__ 함수의 첫 번째 매개변수는 반드시 self 로 선언해야 합니다.





클래스에서 상속이란 A 클래스가 있고 B 클래스가 있을 때, B 클래스에서 A 클래스의 기능을 물려받는 것입니다.
class B클래스(A클래스):
pass
상속을 사용하는 이유 → 기존 클래스를 변경하지 않고 기능을 추가하거나 변경할 때 사용합니다.


class Class_1():
def __init__(self, _a, _b):
self.a = _a # self(자기자신).a(공간이름) = 입력값
self.b = _b
def add_value(self):
result = self.a + self.b
return result
# 클래스 생성
a_class = Class_1(10, 5) # __init__ 자동 호출 → self.a=10, self.b=5
b_class = Class_1(3, 7) # __init__ 자동 호출 → self.a=3, self.b=7
# 내부 변수 접근
print(a_class.a) # 10
print(b_class.a) # 3
# 내부 함수 호출
print(a_class.add_value()) # 15
print(b_class.add_value()) # 10
💡 같은 클래스로 만든 인스턴스는 같은 변수명을 써도 각각 독립된 공간에 저장됩니다.
사칙연산을 수행하는 계산기 클래스입니다.
class Calculate:
def __init__(self, _a, _b):
self.a = _a
self.b = _b
def add(self):
return self.a + self.b
def sub(self):
return self.a - self.b
def multi(self):
return self.a * self.b
def dev(self):
return self.a / self.b
# 생성
cal_1 = Calculate(10, 5)
cal_2 = Calculate(3, 7)
print(cal_1.add(), cal_1.sub(), cal_1.multi(), cal_1.dev()) # 15 5 50 2.0
print(cal_2.add(), cal_2.sub(), cal_2.multi(), cal_2.dev()) # 10 -4 21 0.42...

pandas의 inplace 옵션처럼, 원본 수정 여부를 매개변수로 제어하는 패턴입니다.
class Test2:
def __init__(self, _a):
self.a = _a
def func_1(self, inplace=False):
if inplace:
self.a = self.a ** 2 # 원본 수정
else:
result = self.a ** 2
return result # 원본 유지, 결과만 반환
test_class2 = Test2(5)
test_class2.func_1() # 25 반환, self.a는 5 유지
print(test_class2.a) # 5
test_class2.func_1(inplace=True) # self.a가 25로 변경
print(test_class2.a) # 25
💡
print()vsreturn차이
print() return 역할 화면에 출력 (로그 확인용) 값을 되돌려줌 저장 불가능 변수에 저장 가능 jupyter 출력됨 셀에서 확인 가능
⚠️
inplace=False를 기본값으로 쓰는 이유 → 원본 수정은 사용자가 명시적으로 선택하도록 하기 위해
*args)
함수를 만들 때 데이터를 '바구니째' 처리할 것인지, '내용물 하나하나' 따로 처리할 것인지에 따라 *를 쓸지 결정합니다.
test_func(*a_list) : 리스트의 내용물만 뽑아서 각각의 변수에 전달 (언패킹)test_func(a_list) : 리스트라는 바구니 자체를 전달 → TypeError 오류 발생# *매개변수 → 여러 인자를 하나로 묶음 (패킹)
# *인자 → 묶인 데이터를 풀어서 전달 (언패킹)
def test_func(a, b, c):
a += 1
b += 2
c += 3
return [a, b, c]
a_list = [1, 2, 3]
print(test_func(*a_list)) # [2, 4, 6]
print(a_list) # [1, 2, 3] → 원본 유지
💡
*언패킹은 리스트의 주소를 참조하지 않고 각 원소의 값을 복사합니다.
반면b_list = a_list는 같은 주소를 참조하므로 한 쪽 수정 시 양쪽 모두 변경됩니다.
def test_func2(a, b, c):
a.append(1)
b.pop()
c.reverse()
return [a, b, c]
c_list = [[1, 2], [3, 4], [5, 6]]
print(test_func2(*c_list))
print(c_list) # ⚠️ 원본도 변경됨! (내부 리스트는 참조 전달)
⚠️ 2차원 이상에서는 내부 리스트 자체의 주소가 전달되므로 원본이 변경됩니다.
다른 클래스의 기능을 가져와 사용하는 방법입니다.
# 부모 클래스
class A:
def __init__(self, _name, _age):
self.name = _name
self.age = _age
def user_info(self):
print(f"이름: {self.name}, 나이: {self.age}")
# 자식 클래스 — A를 상속
class B(A):
def __init__(self, _name, _age, _addr):
super().__init__(_name, _age) # 부모 생성자 호출
self.addr = _addr
def user(self):
print(f"이름: {self.name}, 나이: {self.age}, 주소: {self.addr}")
user_2 = B('park', 20, '서울')
user_2.user() # 자식 함수 호출
user_2.user_info() # 부모 함수도 사용 가능
💡 자식 클래스에서 부모 클래스의 생성자 변수를 사용하려면
super().__init__()으로 부모 생성자를 직접 호출해야 합니다.
부모 클래스의 메서드를 자식 클래스에서 같은 이름으로 재정의하는 방법입니다.
부모 클래스의 원본 함수는 그대로 유지됩니다.
from typing_extensions import override # python 3.12 미만
# from typing import override # python 3.12 이상
class Parent:
def user_info(self):
print("부모: 이름, 나이 출력")
class Child(Parent):
@override
def user_info(self):
print("자식: 이름, 나이, 주소 출력") # 덮어씌움
p = Parent()
c = Child()
p.user_info() # 부모: 이름, 나이 출력
c.user_info() # 자식: 이름, 나이, 주소 출력

파이썬은 기본적으로 오버로딩을 지원하지 않습니다.
functools.singledispatch를 사용하면 인자 타입에 따라 다른 함수를 실행할 수 있습니다.
from functools import singledispatch
@singledispatch
def show(data):
print(f'기본형 함수: {data}')
@show.register(int)
def _(data):
print(f'정수형 함수: {data}')
@show.register(list)
def _(data):
print(f'리스트형 함수: {data}')
show('a') # 기본형 함수: a
show(10) # 정수형 함수: 10
show([1,2,3]) # 리스트형 함수: [1, 2, 3]
💡
if type(data) == int방식으로 직접 분기해도 동일하게 구현할 수 있습니다.
class Bank:
total_cost = 0 # 클래스 변수 — 모든 인스턴스가 공유
user_cnt = 0 # 클래스 변수 — 생성된 계좌 수
def __init__(self, _name, _birth, _cost=0):
self.name = _name
self.birth = _birth
self.cost = _cost
self.log = [] # ⚠️ 기본값을 []로 두면 공유 버그 발생 → 생성자 안에서 직접 생성
Bank.total_cost += _cost
Bank.user_cnt += 1
def add_cost(self, _c):
self.cost += _c
self.log.append({'type': '입금', 'cost': _c, 'total_cost': self.cost})
Bank.total_cost += _c
print(f"입금 완료. 현재 잔액: {self.cost}")
def sub_cost(self, _c):
if self.cost >= _c:
self.cost -= _c
self.log.append({'type': '출금', 'cost': _c, 'total_cost': self.cost})
Bank.total_cost -= _c
print(f"출금 완료. 현재 잔액: {self.cost}")
return 1 # 성공
else:
print('잔액이 부족합니다')
return 0 # 실패
def user_info(self):
print(f'이름: {self.name}, 생년월일: {self.birth}, 잔액: {self.cost}')
⚠️
_log=[]버그 주의
생성자 매개변수 기본값으로[]를 쓰면 모든 인스턴스가 같은 리스트를 공유합니다.
반드시 생성자 내부에서self.log = []로 생성하세요.
from typing_extensions import override
class User(Bank):
# 클래스 변수 — 모든 유저가 공유하는 데이터
work_type = {
'A': 11000,
'B': 15000,
'C': 20000
}
item_list = {
'텀블러': 50000,
'스위치': 730000,
'태블릿 거치대': 20000,
'헤드셋': 520000,
'노트북': 2000000
}
def __init__(self, _name, _birth, _cost):
super().__init__(_name, _birth, _cost)
self.items = [] # 구매한 물건 목록
# 일하기 — 시급 * 시간 → 입금
def work(self, _type, _time):
if _type in User.work_type:
amount = User.work_type[_type] * _time
super().add_cost(amount)
else:
raise ValueError('저장되어 있는 일의 종류가 아닙니다.')
# 물건 구매 — 출금 성공 시 items에 추가
def buy_item(self, _item):
try:
result = super().sub_cost(User.item_list[_item])
if result:
self.items.append(_item)
print('구매 성공')
else:
print('구매 실패')
except Exception as e:
print(type(e).__name__)
print('물건의 정보가 없습니다.')
# 오버라이드 — 부모의 user_info()를 덮어씌움
@override
def user_info(self):
print(f'이름: {self.name}, 생년월일: {self.birth}, 잔액: {self.cost}, 구매 목록: {self.items}')
test_user = User('kim', '950101', 0)
test_user.work('C', 20) # C타입 20시간 → 400,000원 입금
test_user.buy_item('텀블러') # 50,000원 출금 → 구매 성공
test_user.buy_item('노트북') # 잔액 부족 → 구매 실패
test_user.user_info()
# 부모 클래스에서 user_info() 호출 시 Bank의 함수 실행
bank1 = Bank('lee', '000101')
bank1.user_info() # 이름, 생년월일, 잔액만 출력

| 개념 | 설명 |
|---|---|
__init__ | 클래스 생성 시 자동 호출되는 생성자 함수 |
self | 클래스 자기 자신의 공간을 가리키는 참조 |
super() | 부모 클래스에 접근하는 방법 |
| 클래스 변수 | 모든 인스턴스가 공유하는 변수 (Bank.total_cost) |
| 인스턴스 변수 | 각 인스턴스가 독립적으로 가지는 변수 (self.cost) |
| 상속 | class 자식(부모) 형태로 부모 기능 재사용 |
| 오버라이드 | 부모 메서드를 자식에서 같은 이름으로 재정의 |
| 오버로딩 | 같은 함수를 인자 타입에 따라 다르게 동작 (singledispatch) |
💡 모듈 / 라이브러리 / 프레임워크 차이
- 모듈 : 하나의
.py파일- 라이브러리 : 여러 모듈을 모아둔 폴더
- 프레임워크 : 여러 라이브러리를 모아둔 것