클래스란?
파이썬은 객체 지향 언어로 클래스를 활용할 수 있다는 장점이 있다.
클래스는 객체를 생성하기 위한 설계도이며 내부에는 속성과 메서드를 정의하게 된다.
이를 통해 특정 기능을 수행하는 객체를 생성할 수 있다.
클래스에 사용되는 용어들
클래스에서는 많은 용어들이 사용되고 헷갈리기가 쉽다.
그러므로 클래스 예제를 통해 용어들을 알아보도록 하자.
class 붕어빵틀:
def __init__(self, 동네, 종류, 가격): # 메서드
self.동네 = 동네 # 속성
self.종류 = 종류
self.가격 = 가격
붕어빵 = 붕어빵틀("서울", "팥", 2000) # 객체 혹은 인스턴스
1. 객체와 인스턴스
객체와 인스턴스는 거의 비슷한 의미이지만 어떻게 말하는가에 따라 용어가 바뀐다.
위 코드에서 붕어빵만을 말하고 싶다면 객체라고 하며 붕어빵틀과 붕어빵과의 관계를 말하고 싶다면 인스턴스라고 한다.
1. 붕어빵은 객체이다.
2. 붕어빵은 붕어빵틀 클래스의 인스턴스이다.
2. 속성과 인스턴스 변수
속성과 인스턴스 변수는 객체의 상태나 데이터를 저장하는 변수이며, self에는 인스턴스의 주소가 들어가 있다.
인스턴스 변수는 앞에 self가 붙은 변수를 뜻하며 이보다 더 넓은 뜻인 속성은 인스턴스 변수와 나중에 배울 클래스 속성을 모두 포함한다.
3. 메서드
메서드는 클래스 내부에 들어가 있는 함수를 뜻하며 객체의 동작을 정의한다.
메서드를 정의할 때는 매개변수 자리에 self가 들어가 있으며 나머지는 사용자 정의 함수와 비슷하다.
4. 생성자
생성자는 메서드이지만 메서드명이 __init__인 메서드로 클래스 호출 시 자동으로 실행되는 특수 메서드이다.
클래스의 기본 사용
클래스는 안에 메서드(함수)와 속성(변수)으로 이루어져 있다고 생각하면 된다.
그리고 클래스를 만들 때는 항상 생성자를 정의해주어야 한다.
class Person: # 클래스 정의
def __init__(self, name, age): # 생성자
self.name = name
self.age = age
def info(self): # 메서드
print(self.name, self.age)
person1 = Person("홍길동", 20) # 객체 생성
person1.info() # 메서드 호출
홍길동 20
클래스의 다양한 기능
클래스에서는 다양한 가능들이 있다.
대표적인 기능을 소개할 텐데 중요한 것들이니 집중하길 바란다.
1. 비공개 속성
위에서는 속성을 클래스 외부에서도 호출할 수 있었다.
하지만 중요한 개인정보 등은 외부에서 호출되면 안 되기 때문에 비공개 속성으로 만들어준다.
비공개 속성은 속성명 앞에 언더바를 두 개 붙이는 것으로 만들 수 있다.
# 일반 속성은 외부에서 호출 가능
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age
def info(self):
print(self.name, self.age)
person1 = Person("홍길동", 20)
person1.name
'홍길동'
# 비공개 속성은 외부에서 호출 불가능
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age
def info(self):
print(self.name, self.age)
person1 = Person("홍길동", 20)
person1.__age
AttributeError: 'Person' object has no attribute '__age'
2. 클래스 속성
지금까지의 속성은 인스턴스마다 독립적이었지만 클래스 속성은 모든 인스턴스와 값을 공유한다.
클래스 속성은 메서드 밖에 일반 변수를 선언하듯이 선언한다.
# 클래스 속성
class Person:
address = [] # 클래스 속성
def __init__(self, name, address):
self.name = name
self.address.append(address)
def info(self):
print(self.name, self.age)
person1 = Person('홍길동', '서울')
person2 = Person("신짱구", '부산')
print(person1.address)
print(person2.address)
['서울', '부산']
['서울', '부산']
또한 위에서 설명했듯이 속성명 앞에 언더바 두 개를 붙이면 클래스 속성도 비공개로 바꿀 수 있다.
3. 정적 메서드
정적 메서드는 인스턴스를 통하지 않고 클래스로 바로 호출이 가능한 메서드이다.
그래서 메서드의 매개변수를 정의할 때 self를 쓰지 않는다.
class Calc:
def __init__(self, n1, n2):
self.n1 = n1
self.n2 = n2
# 정적메소드 만드는 방법
@staticmethod
def add(a, b):
print(a + b)
Calc.add(1, 3)
4
4. 클래스 메소드
클래스 메서드는 클래스 속성에 접근하는 등의 기능을 한다.
클래스 메소드는 정적 메서드와 같이 self를 쓰지 않지만 클래스를 가리키는 cls를 대신 써준다.
class Counter:
count = 0 # 클래스 속성
def __init__(self):
Counter.count += 1 # 인스턴스가 만들어질때마다 클래스속성에 1을 추가한다.
@classmethod
def print_count(cls):
print("인스턴스 개수 : ", cls.count) # cls는 Person을 가리키므로 결국 Person.count와 똑같다.
print("인스턴스 개수 : ", Counter.count)
james = Counter()
maria = Counter()
Counter.print_count()
인스턴스 개수 : 2
인스턴스 개수 : 2
클래스 상속
부모와 자녀의 관계와 같이 클래스도 상속이라는 개념이 있다.
새로운 클래스명 옆 괄호에 기존 클래스명을 넣어주면 상속이 되며 새로운 클래스의 인스턴스로 기존 클래스의 메서드를 사용할 수 있다.
# 상속
class Parents:
def greeting(self):
print("안녕하세요")
class Child(Parents):
def study(self):
print("공부중입니다.")
kim = Child()
kim.greeting()
kim.study()
안녕하세요
공부중입니다.
만약 파생 클래스에서 기반 클래스의 속성을 그냥 호출하면 어떻게 될까?
class Person:
def __init__(self):
self.age = 50
def greeting(self):
print("안녕하세요")
class Student(Person):
def __init__(self):
self.address = "서울"
def study(self):
print("공부중입니다.")
kim = Student()
print(kim.age)
AttributeError: 'Student' object has no attribute 'age'
이처럼 에러가 발생하는 이유는 기반 클래스의 생성자가 호출되지 않아 age라는 속성이 없기 때문이다.
만약 파생 클래스에 생성자가 없다면 기반 클래스의 생성자를 자동 호출하지만 파생 클래스에 생성자가 있다면 기반 클래스의 생성자는 우리가 따로 호출해줘야 한다.
class Person:
def __init__(self):
self.age = 50
self.address = "서울"
def greeting(self):
print("안녕하세요")
class Student(Person):
def __init__(self):
self.address = "서울"
super().__init__() # 기반 클래스의 생성자 호출
def study(self):
print("공부중입니다.")
kim = Student()
print(kim.age)
50
만약 기반 클래스에 있는 메서드를 파생 클래스에서는 다른 기능으로 바꾸고 싶다면 어떻게 해야 할까?
바로 메서드 오버라이딩이라는 기능을 사용하면 된다.
class Parents:
def greeting(self):
print("안녕하세요")
class Child(Parents):
def greeting(self):
super().greeting()
print("공부중입니다.")
kim = Child()
kim.greeting()
이런 식으로 super().함수명을 통해 기반 클래스의 메서드 기능을 가져올 수 있고 밑에 코드를 추가함으로써 기능을 추가하여 더 편리하게 클래스를 설계할 수 있다.
다음은 기반 클래스가 여러 개인 다중상속에 대해 알아보겠다.
다중 상속은 일반적인 상속과 똑같은 방법으로 상속을 진행하며 기반 클래스명만 여러 개 써주면 된다.
class A:
def greeting(self):
print("안녕하세요")
class B:
def hello(self):
print("반갑습니다.")
class C(A, B): # 기반 클래스가 A와 B이다.
def hi(self):
print("어서오세요")
greet = C()
greet.greeting()
greet.hello()
greet.hi()
안녕하세요
반갑습니다.
어서오세요
하지만 다중 상속은 상속의 순서 등 복잡한 요소들이 많아서 주의하며 사용해야 한다.
기반 클래스를 설계할 때 나중에 반드시 구현해야 할 메서드를 추상 메서드로 만든다.
기반 클래스의 추상 메서드는 기능이 없으므로 pass를 넣어주고 추상 클래스에서 기반 클래스의 추상 메서드를 구현하지 않을 경우 밑 예제처럼 에러가 발생한다.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod # 추상 클래스
def sound(self):
pass
class Dog(Animal): # 기반 클래스의 추상 클래스 구현X
pass
dog = Dog()
TypeError: Can't instantiate abstract class Dog without an implementation for abstract method 'sound'
위처럼 에러가 발생하므로 기반 클래스에 추상 메서드는 꼭 파생 클래스에 구현하도록 해야 한다.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod # 추상 클래스
def sound(self):
pass
class Dog(Animal): # 기반 클래스의 추상 클래스 구현O
def sound(self):
print("멍멍멍")
dog = Dog()
dog.sound()
멍멍멍
결론
사실 처음에는 클래스가 생소하기도 하고 클래스에 관련된 개념들이 너무 많아서 와닿지 않을 수 있다.
나중에도 클래스는 많이 나오므로 지금 당장 이해하지 않아도 된다.
'Python > Foundation' 카테고리의 다른 글
12강. [Python]람다 (0) | 2025.02.02 |
---|---|
11강. [Python]함수 (0) | 2025.02.02 |
10강. [Python]반복문 (0) | 2025.02.02 |
09강. [Python]조건문 (0) | 2025.02.02 |
08강. [Python]세트 (0) | 2025.02.02 |