1. 프로그래밍 방법론
프로그래밍 방법론은 프로그램을 개발하는 다양한 접근 방식이나 철학을 의미한다.
프로젝트의 규모, 요구 사항, 개발 팀의 특성에 따라 적합한 방법론이 달라지기 때문에 각 방법론의 특징과 장단점을 이해하는 게 중요하다.
1.1 절차적 프로그래밍(Procedural Programming)
절차(Procedure)를 중시하는 방식으로, 작업을 순서대로 실행하도록 프로그램을 구성한다.
사실 지금까지 파이썬에서 주로 작성했던 코드들은 대부분 절차적 프로그래밍 방식에 가까웠다.
절차적 프로그래밍에서는 코드가 명령문으로 이루어져 있고, 작업 순서가 중요하다.
변수와 함수가 함께 사용되며, 함수를 통해 프로그램의 기능을 분리하고, 코드 중복을 줄일 수 있다.
1.2 객체지향 프로그래밍 (Object-Oriented Programming, OOP)
객체(Object)라는 개념을 사용해 프로그램을 구성한다.
객체는 데이터(속성)와 함수(메서드)를 하나의 단위로 묶은 것을 말한다.
클래스라는 틀을 이용해 객체를 정의하고, 이를 통해 여러 개의 객체를 생성할 수 있다.
캡슐화(Encapsulation), 상속(Inheritance), 다형성(Polymorphism) 등의 특징을 활용해 코드를 재사용하고 확장할 수 있다.
1.3 함수형 프로그래밍 (Functional Programming)
함수형 프로그래밍은 함수를 중심으로 프로그램을 구성한다.
또한, 수학적인 함수 개념에 기초하고 있으며 코드가 간결하고 직관적이다.
예를 들어 map, filter, reduce 등의 함수나 재귀를 주로 사용하여 데이터 처리를 간결하게 수행할 수 있다.
2. 클래스
클래스(class)는 객체지향 프로그래밍에서 데이터(속성)와 기능(메서드)을 하나로 묶어 객체를 만들기 위한 설계도(템플릿)이다.
클래스를 정의하면, 그 구조를 기반으로 여러 개의 객체(인스턴스)를 생성할 수 있고, 각 객체는 동일한 구조를 가지면서도 서로 다른 값을 가질 수 있다.
class 클래스이름:
# 클래스 속성(멤버 변수) 정의
속성1 = 초기값1
속성2 = 초기값2
# 생성자 메서드 (생략 가능)
def __init__(self, 매개변수1, 매개변수2, ...):
# 인스턴스 속성 초기화
self.속성1 = 매개변수1
self.속성2 = 매개변수2
# 메서드(멤버 함수) 정의
def 메서드1(self, 매개변수1, 매개변수2, ...):
# 메서드 동작 정의
pass
def 메서드2(self, 매개변수1, 매개변수2, ...):
# 메서드 동작 정의
pass
✔️ 객체를 만들기 위해서는 먼저 설계도가 필요하다.
왜냐하면 설계도가 있으면
① 좀 더 명확하게 만들 수 있고,
② 여러 개의 객체를 만들 수도 있기 때문이다.
파이썬에서는 이 설계도를 클래스(class)라고 부른다. 클래스에는 두가지 요소가 필요하다.
이를 사람으로 비유하면 이해가 쉽다.
사람은 이름, 키, 몸무게 같은 특징(명사)이 있고,
먹는다, 잔다, 걷는다 같은 행동(동사)이 있다.
클래스도 비슷한 방식으로 이해할 수 있다.
- 명사에 해당하는 부분 →
속성(attribute) - 동사에 해당하는 부분 →
메서드(method)
3. 객체(인스턴스) 생성
클래스를 정의한 후에는 이를 기반으로 객체(인스턴스)를 생성할 수 있다.

👉 붕어빵 틀(클래스)이 하나 있더라도 붕어빵(객체)은 여러 개 만들 수 있다.
👉 즉, 클래스는 객체를 만들기 위한 틀이고, 객체는 그 틀을 기반으로 실제 생성된 결과물이다.
예시
Fruit()를 통해 apple과 banana 객체를 각각 생성했다.
class Fruit:
pass # 일단 비워두는 코드, 나중에 내용을 추가할 때 사용
apple=Fruit()
print(apple)
print(type(apple))
print(id(apple))
print("================")
banana= Fruit()
print(banana)
print(type(banana))
print(id(banana))
실행 결과

👉 type()을 출력해보면 둘 다 Fruit 클래스로부터 만들어졌다는 것을 알 수 있다.
👉 id() 값을 보면 서로 다른 값이 출력된다.
👉 즉, 같은 Fruit 클래스를 기반으로 생성되었더라도 실제 객체는 각각 독립적으로 생성된다는 뜻이다.
그렇다면 메모리상에서는 객체가 어떻게 생성되는 걸까?

위 다이어그램처럼 apple과 banana는 각각 다른 메모리 공간을 참조한다.
👉 같은 Fruit 클래스로 만들어졌더라도 실제 객체는 서로 독립적으로 존재한다.
👉 다만 객체를 만들기 위한 틀인 Fruit 클래스는 공통으로 사용된다.
🔸 객체와 인스턴스
객체(object)와 인스턴스(instance)는 거의 같은 의미로 사용되지만, 관점에 따라 구분된다.
객체→ 메모리에 생성된 실체 자체를 강조할 때인스턴스→ "어떤 클래스에서 만들어졌는지" 관계를 강조할 때
의 차이 정도로 이해하면 된다.
4. 생성자
파이썬에서 생성자(Constructor)는 클래스의 인스턴스가 생성될 때 자동으로 호출되는 특별한 메서드 이다.
생성자는 객체의 초기화를 담당하며, 객체가 생성될 때 필요한 속성을 초기화하고 설정하는 역할을 한다.
파이썬에서 생성자 메서드는 __init__라고 이름이 정해져 있다.
속성은 self를 사용하여 접근하고 설정한다.
이렇게 초기화된 속성은 객체가 생성될 때마다 다른 값을 가질 수 있다.
class 클래스이름:
# 생성자
def __init__(self, 매개변수1, 매개변수2):
self.속성1 = 매개변수1
self.속성2 = 매개변수2
🔸 인스턴스 변수
인스턴스 변수는 객체마다 각각 따로 가지는 변수이다.
객체가 생성될 때 self 키워드를 통해 만들어지고, 각 객체가 서로 다른 값을 저장할 수 있다.
예를 들어 같은 Fruit 클래스라도
apple객체의quantity= 10banana객체의quantity= 5
처럼 서로 다른 데이터를 가질 수 있다
또한, 인스턴스 변수는 객체명.변수명 형태로 접근한다.
예시
이번에는 인스턴스 변수가 실제 객체마다 어떻게 다른 값을 가지는 지 직접 확인해보자.
class Fruit:
def __init__(self,name,quantity, origin='원산지 미상'):
self.name=name
self.quantity=quantity
self.origin=origin
apple=Fruit('사과',10,'한국')
print(apple)
print(apple.name)
print(apple.quantity)
print(apple.origin)
print()
banana= Fruit('바나나',5,'필리핀')
print(banana)
print(banana.name)
print(banana.quantity)
print(banana.origin)
실행 결과

👉 실행 결과를 보면 Fruit 클래스로 생성되었더라도 객체마다 저장된 값이 서로 다르다는 것을 확인할 수 있다.
5. 메서드
메서드(method)는 클래스 내부에 정의된 함수로,
객체(인스턴스)나 클래스와 관련된 동작(행동)을 수행하는 기능한다.
파이썬에서는 메서드의 종류에 따라
self를 사용하는인스턴스 메서드cls를 사용하는 클래스 메서드(@classmethod)- 별도의 참조 없이 독립적으로 동작하는 정적 메서드(
@staticmethod)로 나뉜다
메서드는 단순한 함수와 달리 특정 객체나 클래스와 연결되어 동작하며, 객체의 상태(속성)를 읽거나 변경하는 역할을 한다.
🔸 인스턴스 메서드
앞서 설명한 것처럼 인스턴스 메서드는 self를 사용하는 메서드이다.
인스턴스 메서드는 객체의 데이터를 사용하거나, 객체의 값을 변경할 때 사용한다.
예시 1
이번에는 인스턴스 메서드가 실제로 어떻게 동작하는지 간단한 예제로 살펴보자.
아래 코드에서
print_info()는 과일 정보를 출력하고,add_quantity()는 과일의 수량을 증가시키는 역할을 한다.


두 메서드 모두 객체 내부의 데이터를 사용하기 때문에 self를 사용한다.
👉 그렇다면 여기서 print_info()와 add_quantity() 같은 메서드는 객체마다 새로 만들어지는 걸까?

위 다이어그램처럼 apple과 banana 객체는 각각 독립적으로 생성된다.
하지만 print_info()와 add_quantity() 같은 인스턴스 메서드는 객체마다 새로 만들어지는 것이 아니라,
클래스 내부에 한 번만 만들어지고 여러 객체가 공용으로 사용된다.
만약 객체마다 메서드가 새로 생성된다면 메모리를 많이 사용하게 된다.
하지만 인스턴스 메서드는 클래스에 한 번만 존재하고 여러 객체가 공유해서 사용하기 때문에 메모리를 효율적으로 사용할 수 있다.
예시 2
메서드 종류를 한 번에 보기 위해 간단한 주문(Order) 예시를 살펴보자.
- 인스턴스 메서드 → 객체마다 다른 값을 사용
- 클래스 메서드 → 클래스 전체 값을 변경
- 정적 메서드 → 객체 상태와 상관없는 독립 기능
class Order:
tax_rate = 0.1 # 클래스 변수 (세율: 모든 주문 공통)
def __init__(self, price, quantity):
self.price = price # 상품 가격
self.quantity = quantity # 수량
# 인스턴스 메서드
def total_price(self):
return self.price * self.quantity
# 클래스 메서드
@classmethod
def set_tax_rate(cls, rate):
cls.tax_rate = rate
# 정적 메서드
@staticmethod
def calculate_discount(price, discount_rate):
return price * (1 - discount_rate)
# 인스턴스 생성
order1 = Order(10000, 2) # 10000원 상품 2개
# 인스턴스 메서드 호출
print("총 가격:", order1.total_price()) # 20000
# 정적 메서드 사용 (할인 계산)
discounted = Order.calculate_discount(order1.total_price(), 0.2)
print("할인 적용 가격:", discounted) # 16000
# 클래스 메서드 사용 (세율 변경)
Order.set_tax_rate(0.2)
print("변경된 세율:", Order.tax_rate) # 0.2
실행 결과
총 가격: 20000
할인 적용 가격: 16000.0
변경된 세율: 0.2
위 코드에서
👉 total_price()는 인스턴스 메서드이다.
각 객체의 price, quantity 값을 사용해야 하기 때문에 self를 사용한다.
👉 set_tax_rate()는 클래스 메서드이다.
tax_rate(클래스 변수)처럼 모든 주문이 공통으로 사용하는 값을 수정할 때 사용한다.
👉 calculate_discount()는 정적 메서드이다.
객체 상태와 관계없이 단순 계산만 수행하기 때문에 self나 cls가 필요 없다.
🔸 데코레이터
데코레이터(decorator)는 기존 함수나 메서드를 수정하지 않고,
함수에 새로운 기능을 덧붙이는 문법이다.
쉽게 말하면 함수를 한 번 감싸서 기능을 추가하는 느낌에 가깝다.
파이썬에서는 @ 문법을 사용한다.
예를 들어 앞에서 사용한
@classmethod@staticmethod
도 데코레이터의 일종이다.
🔸 클래스 변수
클래스 변수는 클래스에 속하는 변수로, 클래스 전체가 공유하는 변수이다.
즉, 같은 클래스로 생성된 객체들은 하나의 값을 함께 참조한다.
그래서 클래스 변수를 변경하면 모든 객체에도 반영된다.
다만 특정 객체에서 같은 이름으로 값을 새로 만들면(덮어쓰기), 그 객체만 별도의 값을 가지게 된다.
예시 3
이번에는 클래스 변수와 인스턴스 변수가 어떻게 다르게 동작하는지 확인해보자.
여기서 origin은 클래스 변수이고, name과 quantity는 인스턴스 변수이다.
class Fruit:
origin= "한국"
def __init__(self, name, quantity):
self.name=name
self.quantity= quantity
def print_info(self):
print(f'원산지 : {Fruit.origin}')
print(f'이름 : {self.name}')
print(f'수량 : {self.quantity}')
apple=Fruit('사과',10)
banana=Fruit('바나나',5)
apple.print_info()
print("=============")
banana.print_info()
print()
# 클래스 변수 origin 변경!
Fruit.origin='필리핀'
print("======= origin(원산지) 변경 후 =========")
apple.print_info()
banana.print_info()
print()
# 인스턴스 변수로 덮어쓰기
# apple의 멤버 변수로 origin 이 없긴 함
# apple의 인스턴스 변수가 생기면서 거기에 미국을 넣는다
apple.origin='미국' # apple만 따로 가짐
print("======== apple 원산지만 미국으로 변경 시도=======")
apple.print_info()
print('apple.origin=', apple.origin)
banana.print_info()
print('banana.origin=',banana.origin)
# 바나나의 인스턴스 변수를 먼저 찾아보고 없으면 클래스 변수를 찾아본다.
# 바나나의 원산지 : 필리핀
실행 결과

실행 결과를 보면 처음에는 apple과 banana 모두 같은 origin 값을 사용한다.

이는 origin이 클래스 변수이기 때문에, 두 객체가 같은 값을 공유하고 있기 때문이다.
이후, Fruit.origin = '필리핀'으로 클래스 변수를 변경하게 되면서,
apple과 banana 모두 변경된 값(‘필리핀’)을 사용한다.

여기서 헷갈릴 수 있는 지점이 있다.
apple.origin = '미국'
를 실행했다고 해서 클래스 변수 자체가 바뀌는 것이 아니다.
이 코드는 apple 객체 안에 새로운 origin 인스턴스 변수를 만드는 것이다.
즉,
Fruit.origin: 여전히 ‘필리핀’apple.origin: ‘미국’banana.origin: 필리핀
처럼 동작한다.
즉 apple만 자기만의 origin 값을 따로 가지게 된 것이다.
banana는 자기 안에 origin 인스턴스 변수가 없기 때문에 클래스 변수 값을 사용한다.
'python' 카테고리의 다른 글
| 자료구조 - 배열(Array) (0) | 2026.05.29 |
|---|---|
| 11. 객체 지향 프로그래밍 4대 패러다임 ① (0) | 2026.05.28 |
| 9. 사용자 정의 함수 ② (0) | 2026.05.28 |
| 9. 사용자 정의 함수 ① (0) | 2026.05.27 |
| Python - 제어문-반복문 (0) | 2026.05.27 |