클래스와 객체
- 클래스를 가장 쉽게 설명해 주는 예시를 살펴보면 붕어빵 틀과 이걸 이용해서 만든 붕어빵이다.
- 붕어빵 틀 = 클래스
- 붕어빵 = 객체
- 클래스는 이렇게 만들 거라는 설계도이고 그 설계도로 실제로 만들어낸 결과물들이 객체이다. 라고 이해하면 된다. 그리고 각각의 객체 속성은 두 가지가 있다 값(숫자, 문자가 저장되는)과 행동을 가지고 있다. 쉽게 말해서 변수는 값이고 행동은 메서드 이걸 찍어 내는 건 클래스다.
class Fishbun: # 클래스 정의
pass # 클래스 내용은 비워둠 (기본만 작성)
# 클래스를 이용해 객체 생성
팥붕어빵 = Fishbun() # 객체1
슈크림붕어빵 = Fishbun() # 객체2
- 클래스라는 예약어를 먼저 쓴다 함수는 def하고 함수 이름을 적어줬으면 클래스는 class라고 적어주고 맨 앞쪽 글자는 대문자로 쓰고 함수 이름을 정해주면 된다. 기본만 보자면 설계도가 있고 클래스를 불러와서 찍어내면 리턴 값으로 인스턴스가 나오게 된다. 그럼 붕어빵 여러 개를 찍어서 변수에 담아줄 수 있다.
인스턴스와 객체의 차이
- 객체(Object)
- 객체는 프로그램 내에서 데이터(속성)와 동작(메서드)을 포함한 독립적인 단위 전체를 의미한다. 파이썬처럼 "모든 것이 객체"인 언어에서는 클래스 자체, 함수, 심지어 숫자나 문자열도 모두 객체라고 부를 수 있다.
- 인스턴스(Instance)
- 인스턴스는 특정 클래스를 이용해 생성된 객체를 말한다. 클래스라는 설계도를 바탕으로 만들어진 구체적인 대상이 바로 인스턴스이다.
모든 인스턴스는 객체지만 객체라는 범위는 인스턴스보다 더 넓은 개념이다. 클래스에 의해서 만들어진 경우에 한정해서 "인스턴스"라고 부른다고 보면 된다.
생성자
- 생성자란 객체가 생성될 때 자동으로 호출되는 메서드를 의미한다. 파이썬에서 메서드명으로 __init__를 사용하면 이 메서드는 생성자가 된다. 즉 클래스로부터 인스턴스를 생성할 때 항상 처음 실행되는 함수이다.
class Fishbun:
def __init__(self, filling, size): # 생성자 정의
self.filling = filling # 속 내용물
self.size = size # 크기
# 클래스를 사용해 객체 생성
팥붕어빵 = Fishbun("red bean", "small") # 생성자가 자동으로 실행
슈크림붕어빵 = Fishbun("custard", "large")
# 생성된 객체의 속성 확인
print(팥붕어빵.filling) # "red bean"
print(슈크림붕어빵.size) # "large"
- 생성자는 self, filling, size를 파라미터로 받는다. self는 생성되는 객체 즉 자기 자신을 의미한다. 왼쪽의 self.filling과 self.size는 객체 속성이고 오른쪽의 filling, size는 생성자 호출 시 전달된 값(내용물 custard이나 red bean)으로 각각의 속성으로 초기화된다. 이렇게 특정 객체에 저장되는 변수는 그 객체만의 고유한 데이터로 이를 객체 변수 또는 속성이라고 부른다.
- 예를 들어:
팥 붕어빵.filling -> "red bean"
슈크림 붕어빵.size -> "large"
- 예를 들어:
클래스 상속
- 클래스를 만들 때 기존 클래스의 기능을 물려받을 수 있다. 클래스를 상속하기 위해서는 아래처럼 클래스 이름 뒤 괄호 안에 상속할 클래스 이름을 넣어주면 된다.
class 클래스_이름(상속할_클래스_이름)
pass. # 추가할 기능이 없을 경우
상속 기능은 왜 쓰는 걸까?
- 기존 클래스를 수정하지 않고 기능을 추가하거나 변경하려고 할 때 사용한다. 쉽게 말해서 휴대폰이라고 생각하면 이해하기 편하다. 기본적인 전화/문자 기능을 가진 모델이 있고 여기에 카메라, 인터넷 같은 기능이 추가된 스마트폰이 출시된다. 이처럼 기존 기능은 그대로 두고 새로운 기능을 추가하거나 기존 기능을 바꾸기 위해 상속을 사용한다.
class Phone: # 기본 클래스
def call(self):
return "Making a call."
class SmartPhone(Phone): # Phone 클래스를 상속받음
def browse(self):
return "Browsing the internet."
# SmartPhone 클래스는 Phone의 기능을 물려받음
basic_phone = Phone()
smartphone = SmartPhone()
print(basic_phone.call()) # "Making a call."
print(smartphone.call()) # "Making a call." (상속받은 기능)
print(smartphone.browse()) # "Browsing the internet." (추가된 기능)
메서드 오버라이딩
- 메서드 오버라이딩은 부모 클래스에서 정의한 메서드를 자식 클래스에서 새롭게 정의(수정) 하는 것을 의미한다. 그럼 언제 사용할까? 부모 클래스의 기본 기능은 유지하면서 자식 클래스에서 동작을 변경하거니 더 구체적인 동작을 정의하고 싶을 때 사용한다.
class Animal:
def speak(self):
return "동물이 소리를 냅니다."
class Dog(Animal): # 자식 클래스
def speak(self): # 부모 클래스의 메서드를 오버라이딩
return "멍멍!"
class Cat(Animal): # 또 다른 자식 클래스
def speak(self): # 부모 클래스의 메서드를 오버라이딩
return "야옹!"
dog = Dog()
cat = Cat()
print(dog.speak()) # 출력: "멍멍!"
print(cat.speak()) # 출력: "야옹!"
클래스 변수
- 클래스 변수는 클래스 정의 내부에서 선언된 변수로 클래스에서 생성된 모든 객체가 공유한다.
class Fishbun:
kind = "붕어빵" # 클래스 변수 (모든 객체가 공유)
def __init__(self, filling):
self.filling = filling # 인스턴스 변수 (객체마다 다름)
# 객체 생성
팥붕어빵 = Fishbun("red bean")
슈크림붕어빵 = Fishbun("custard")
# 클래스 변수 확인
print(팥붕어빵.kind) # "붕어빵" (클래스 변수)
print(슈크림붕어빵.kind) # "붕어빵" (클래스 변수)
# 클래스 변수 수정
Fishbun.kind = "슈붕어빵"
print(팥붕어빵.kind) # "슈붕어빵" (모든 객체에 반영됨)
- 클래스 변수는 지역변수와 헷갈릴 수 있지만 서로 다른 변수이다.
구분 | 클래스 변수 | 지역변수 |
범위 | 클래스 전체에서 공유됨 | 함수나 메서드 내부에서만 유효함 |
생존 기간 | 프로그램이 끝날 때까지 존재 | 함수나 메서드가 종료되면 소멸 |
선언 위치 | 클래스 내부, 메서드 밖에 선언 | 함수나 메서드 내부에서 선언 |
특징 | 모든 객체가 공유함 | 각 실행마다 별도로 생성됨 |
💡 TIP:
클래스 변수는 클래스명.변수명으로 접근하는 것이 좋다.
지역 변수는 함수나 메서드 내부에서 임시로 사용되며 함수가 끝나면 메모리에서 사라진다.