초기의 프로그래밍은 절차를 지향
절차에 따라 명령을 순서대로 실행
단순한 문제나 수식적 해결에 용이하며 관리하기가 편함
그러나, 점점 프로그램이 커지고 컴퓨터의 성능 발달에 따라 해결하고자 하는 문제도 커지고 복잡해짐
이런 문제점을 해결하기 위해 객체 지향 프로그래밍이 등장
프로그램을 객체라는 독립적인 단위로 작성하기 시작
객체 지향 프로그래밍의 핵심인 클래스와 객체 이해하기
- 클래스 : 객체를 만들기 위한 설계도
클래스는 속성(객체의 데이터)과 메서드(객체의 동작)로 구성
- 객체 : 클래스라는 설계도로부터 생성된 구체적인 데이터와 기능을 가지는 실체
- 객체 지향 프로그래밍(Object-Oriented Programming, OPP)의 핵심 개념
클래스와 객체를 사용해 프로그램을 설계하고 구현하는 방식
- OPP의 4가지 원칙
1. 캡슐화 : 객체 내부의 속성과 메서드를 하나로 묶고 객체 내부로 숨기는 원칙
보안성의 장점 : 외부에서의 직접 접근 및 수정 제한
2. 상속 : 이미 생성된 클래스를 새로운 클래스가 물려받는 방법
3. 다형성 : 동일한 이름의 메서드가 여러 객체에서 서로 다른 방식으로 동작 가능한 원칙
ex) 같은 메서드를 호출했으나, 상황에 따라 다른 결과값 출력
4. 추상화 : 복잡한 시스템 단순화를 통해 필요한 부분만 노출하고 나머지는 감추는 원칙
클래스 만들기와 속성, 메서드 살펴보기
- 클래스 정의하기
class Cat: # 'Cat'이라는 클래스를 정의함
pass # 클래스가 비어있을 때 사용 (필수 X)
- 속성 정의하기
class Cat:
def __init__(self, name, breed): # 속성을 초기화하는 생성자 메서드
self.name = name # 이름 속성
self.breed = breed # 품종 속성
__init__ : 해당 클래스를 바탕으로 객체를 만들 때 최초로 자동으로 호출되는 함수
속성을 초기화하는 생성자 메서드 역할 / 객체의 초기 속성을 설정하는 역할
self : 현재 메서드가 호출된 객체를 자동으로 전달하는 역할
위치가 정해져 있으며, 클래스 내에서 메서드를 정의할 때 항상 첫 번째 매개변수로 사용됨
- 메서드 정의하기
class Cat:
def __init__(self, name, breed):
self.name = name
self.breed = breed
def bark(self): # 'bark'라는 메서드를 정의
print(f"{self.name}: Meow")
def introduce(self): # 'introduce'라는 메서드를 정의
print(f"이름: {self.name}, 품종: {self.breed}")
- 객체를 생성하고 메서드 호출하기
# 'Cat' 클래스의 객체 생성
Abel = Cat("Abel", "Persian")
Abel.name, Abel.breed # ('Abel', 'Persian')
# 객체의 매서드 호출
Abel.bark() # Abel: Meow
Abel.introduce() # 이름: Abel, 품종: Persian
- 매직 메서드 : 파이썬에서 미리 정의된 메서드
1. __init__ : 객체 생성 시 호출되는 생성자 메서드, 객체의 초기화 담당
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
2. __repr__ : 객체의 공식적인 문자열을 반환하는 메서드
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Person('{self.name}', {self.age})"
3. __add__ : 객체 간의 덧셈 연산을 정의하는 메서드 / + 연산자 재정의
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __add__(self, other):
print(self.name + other.name)
print(self.age + other.age)
lee = Person("beady", 30)
son = Person("heungmin", 32)
lee + son
# beadyheungmin
# 62
4. __eq__ : 두 객체가 같은지 비교하는 메서드 / == 연산자 재정의
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if self.name == other.name:
print("동일한 이름입니다.")
else:
print("다른 이름입니다.")
lee = Person("beady", 30)
son = Person("heungmin", 32)
lee == lee # 동일한 이름입니다.
lee == son # 다른 이름입니다.
5. __str__ : 객체의 비공식적인 문자열을 반환하는 메서드
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name}는 {self.age}살입니다."
lee = Person("beady", 30)
son = Person("heungmin", 32)
print(lee) # beady는 30살입니다.
print(son) # heungmin는 32살입니다.
- 클래스 메서드 : 클래스 자체를 인수로 받는 메서드
class MyClass:
class_variable = 0 # 클래스 변수 선언 / 해당 클래스 및 클래스로 만든 모든 객체가 공유
@classmethod # 클래스 메서드 정의
def increment(cls):
cls.class_variable += 1
# 클래스 메서드 호출
MyClass.increment()
print(MyClass.class_variable) # 1
# increment 메서드는 클래스 변수인 class_variable의 값을 증가시킴
# increment 메서드는 객체가 아닌 클래스 자체에서 호출
- 정적 메서드 : 클래스나 객체와는 관련 없지만, 클래스의 논리적 흐름에서는 의미가 있는 메서드
첫번째 매개변수로 self나 cls를 받지 않음
class Utility:
@staticmethod
def add(x, y):
return x + y
# 정적 메서드 호출
Utility.add(6, 4) # 10
- 상속 : 기존(부모) 클래스의 속성과 메서드를 새로운(자식) 클래스가 물려받아 사용하는 개념
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "소리를 냅니다."
def type(self):
return "동물입니다."
class Dog(Animal): # 기존의 Animal 클래스를 상속받아 새로운 Dog 클래스 정의
def speak(self): # 부모 클래스의 메서드를 재정의 (메서드 오버라이딩)
return f"{self.name}가 멍멍 짖습니다."
# 객체 생성
dog = Dog("Buddy")
print(dog.speak()) # Buddy가 멍멍 짖습니다.
print(dog.type()) # 동물입니다. (부모 클래스 메서드 활용)