Python 클래스 메서드 종류: 인스턴스 메서드, 클래스 메서드, 정적 메서드

Ad Placeholder

앞선 글에서는 Python 클래스의 기본 개념과 객체, 인스턴스, __init__(), self에 대해 살펴봤습니다.

클래스 안에는 데이터를 저장하는 변수뿐만 아니라 여러 가지 메서드를 정의할 수 있습니다.

그런데 Python에서는 클래스 안의 메서드를 한 가지 방식으로만 사용하는 것이 아닙니다.

대표적으로 다음 세 가지 종류가 있습니다.

  • 인스턴스 메서드(Instance Method)
  • 클래스 메서드(Class Method)
  • 정적 메서드(Static Method)

겉으로 보기에는 모두 클래스 안에 있는 함수처럼 보이지만, 어떤 데이터를 기준으로 동작하는지와 호출 방법에 차이가 있습니다.

이번 글에서는 세 가지 메서드가 어떻게 다른지 하나씩 살펴보겠습니다.

인스턴스 메서드란?

가장 먼저 살펴볼 것은 인스턴스 메서드입니다.

앞선 글에서 사용했던 다음과 같은 메서드가 인스턴스 메서드입니다.

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(f"{self.name}, {self.age}살입니다.")

여기서:

def introduce(self):

가 인스턴스 메서드입니다.

인스턴스 메서드의 가장 큰 특징은 첫 번째 매개변수로 일반적으로 self를 사용한다는 것입니다.

self는 현재 메서드를 호출한 인스턴스를 가리킵니다.

인스턴스 메서드에서 self 사용하기

다음 코드를 보겠습니다.

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(f"이름: {self.name}")
        print(f"나이: {self.age}")

객체를 만들어보겠습니다.

person = Person("철수", 20)

그리고 메서드를 호출합니다.

person.introduce()

결과:

이름: 철수
나이: 20

여기서 self.name은 person.name을 의미하고, self.age는 person.age를 의미한다고 생각하면 이해하기 쉽습니다.

즉,

person.introduce()

를 개념적으로 다음과 같이 생각할 수 있습니다.

Person.introduce(person)

Python이 메서드를 호출할 때 현재 인스턴스를 자동으로 전달하기 때문에 일반적인 호출에서는 self를 직접 전달하지 않습니다.

인스턴스마다 다른 데이터를 사용할 수 있다

인스턴스 메서드의 중요한 특징은 각 인스턴스의 데이터를 사용할 수 있다는 것입니다.

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(f"{self.name}, {self.age}살입니다.")

이제 두 개의 객체를 만들어보겠습니다.

person1 = Person("철수", 20)
person2 = Person("영희", 25)

person1.introduce()
person2.introduce()

결과:

철수, 20살입니다.
영희, 25살입니다.

같은 introduce() 메서드를 사용하지만 self가 각각 다른 객체를 가리키기 때문에 서로 다른 데이터를 사용합니다.

따라서 객체의 상태를 읽거나 변경해야 하는 메서드라면 인스턴스 메서드가 적합합니다.


클래스 메서드란?

이번에는 클래스 메서드(Class Method)를 살펴보겠습니다.

클래스 메서드는 @classmethod 데코레이터를 사용해서 정의합니다.

class Person:

    count = 0

    @classmethod
    def get_count(cls):
        return cls.count

여기서:

@classmethod

가 클래스 메서드임을 나타냅니다.

그리고 첫 번째 매개변수로 일반적으로 cls를 사용합니다.

def get_count(cls):

cls는 현재 클래스를 가리키는 참조입니다.

즉 self가 인스턴스를 가리킨다면 cls는 클래스를 가리킨다고 이해하면 됩니다.

self → 인스턴스
cls  → 클래스

클래스 변수와 클래스 메서드

클래스 메서드를 이해하려면 클래스 변수도 알아야 합니다.

다음 코드를 보겠습니다.

class Person:

    count = 0

    def __init__(self, name):
        self.name = name
        Person.count += 1

여기서:

count = 0

은 클래스 변수입니다.

인스턴스마다 별도로 존재하는 self.name과 달리 클래스에 속한 값입니다.

객체를 만들 때마다 count를 증가시켜보겠습니다.

person1 = Person("철수")
person2 = Person("영희")
person3 = Person("민수")

print(Person.count)

결과:

3

이런 클래스에 관련된 값을 처리할 때 클래스 메서드를 사용할 수 있습니다.

class Person:

    count = 0

    def __init__(self, name):
        self.name = name
        Person.count += 1

    @classmethod
    def get_count(cls):
        return cls.count

이제 다음과 같이 호출할 수 있습니다.

print(Person.get_count())

결과:

3

클래스 메서드는 특정 인스턴스가 아니라 클래스 자체와 관련된 작업을 수행할 때 유용합니다.

클래스 메서드는 인스턴스에서도 호출할 수 있다

클래스 메서드는 클래스에서 호출할 수도 있고 인스턴스를 통해 호출할 수도 있습니다.

class Person:

    count = 0

    @classmethod
    def get_count(cls):
        return cls.count

다음 두 방식 모두 사용할 수 있습니다.

Person.get_count()

또는:

person = Person()
person.get_count()

다만 클래스와 관련된 기능이라는 의미를 명확하게 전달하기 위해 일반적으로 클래스 메서드는 클래스에서 호출하는 경우가 많습니다.


정적 메서드란?

마지막으로 정적 메서드(Static Method)를 살펴보겠습니다.

정적 메서드는 @staticmethod 데코레이터를 사용합니다.

class Calculator:

    @staticmethod
    def add(a, b):
        return a + b

이 메서드에는 self나 cls가 없습니다.

def add(a, b):

처럼 일반 함수와 비슷하게 작성합니다.

호출은 다음과 같습니다.

result = Calculator.add(10, 20)

print(result)

결과:

30

정적 메서드는 왜 사용할까?

정적 메서드는 클래스와 관련된 기능이지만 특정 인스턴스의 데이터나 클래스의 상태를 사용하지 않을 때 사용할 수 있습니다.

예를 들어 계산 기능을 생각해보겠습니다.

class Calculator:

    @staticmethod
    def add(a, b):
        return a + b

    @staticmethod
    def multiply(a, b):
        return a * b

이 메서드들은 특정 Calculator 객체의 데이터가 필요하지 않습니다.

따라서 다음과 같이 사용할 수 있습니다.

print(Calculator.add(10, 20))
print(Calculator.multiply(10, 20))

결과:

30
200

일반 함수로 만들어도 동작할 수 있지만, Calculator와 관련된 기능이라는 의미를 클래스 내부에 표현할 수 있습니다.


세 가지 메서드 비교

이제 세 가지 메서드를 비교해보겠습니다.

종류데코레이터첫 번째 인자주로 사용하는 대상
인스턴스 메서드없음self인스턴스
클래스 메서드@classmethodcls클래스
정적 메서드@staticmethod없음특정 객체나 클래스 상태가 필요 없는 기능

가장 중요한 차이는 무엇을 기준으로 동작하는가입니다.

인스턴스 메서드
    ↓
self
    ↓
현재 객체의 데이터 사용

클래스 메서드
    ↓
cls
    ↓
클래스의 데이터 사용

정적 메서드
    ↓
self / cls 없음
    ↓
객체나 클래스의 상태에 직접 의존하지 않음

하나의 클래스에서 세 가지를 함께 사용하기

세 가지 메서드를 하나의 클래스에 함께 사용할 수도 있습니다.

class Person:

    count = 0

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Person.count += 1

    def introduce(self):
        print(f"{self.name}, {self.age}살입니다.")

    @classmethod
    def get_count(cls):
        return cls.count

    @staticmethod
    def is_adult(age):
        return age >= 18

각각의 역할을 보면 다음과 같습니다.

인스턴스 메서드

person.introduce()

특정 사람의 이름과 나이를 사용합니다.

클래스 메서드

Person.get_count()

Person 클래스에 만들어진 객체의 개수를 확인합니다.

정적 메서드

Person.is_adult(20)

특정 사람의 데이터가 필요하지 않고, 단순히 나이만 전달받아 성인 여부를 판단합니다.

이렇게 각각의 역할을 구분할 수 있습니다.


클래스 메서드를 사용하는 또 다른 방법

클래스 메서드는 객체를 생성하는 방법을 추가하는 용도로도 많이 사용됩니다.

예를 들어 다음과 같은 클래스가 있다고 해보겠습니다.

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age

일반적으로는 다음과 같이 객체를 생성합니다.

person = Person("철수", 20)

그런데 데이터가 문자열 형태로 들어온다고 가정해보겠습니다.

철수,20

이 데이터를 이용해서 객체를 생성하고 싶다면 클래스 메서드를 사용할 수 있습니다.

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def from_string(cls, data):
        name, age = data.split(",")
        return cls(name, int(age))

이제 다음과 같이 사용할 수 있습니다.

person = Person.from_string("철수,20")

print(person.name)
print(person.age)

결과:

철수
20

여기서 중요한 부분은:

return cls(name, int(age))

입니다.

cls는 현재 클래스를 가리키므로 결국 새로운 Person 객체를 생성하게 됩니다.

이런 방식을 대체 생성자(alternative constructor)처럼 사용할 수 있습니다.


cls()를 사용하는 이유

앞의 예제에서 다음과 같이 작성할 수도 있을 것 같습니다.

return Person(name, int(age))

하지만 클래스 메서드에서는 다음과 같이 cls를 사용하는 것이 일반적입니다.

return cls(name, int(age))

이렇게 하면 해당 클래스를 상속받은 자식 클래스에서도 더 유연하게 사용할 수 있습니다.

즉 Person이라는 클래스 이름을 코드에 직접 고정하지 않고 현재 클래스를 기준으로 객체를 생성할 수 있습니다.

이 부분은 나중에 상속을 배우면 더욱 자연스럽게 이해할 수 있습니다.


정적 메서드는 일반 함수와 무엇이 다를까?

정적 메서드를 보면 이런 생각이 들 수 있습니다.

그냥 일반 함수로 만들면 되는 것 아닌가?

맞습니다.

정적 메서드는 실제로 일반 함수와 비슷하게 동작합니다.

예를 들어:

def add(a, b):
    return a + b

와:

class Calculator:

    @staticmethod
    def add(a, b):
        return a + b

는 기능적으로 비슷합니다.

차이는 코드의 소속과 의미를 표현하는 방법에 있습니다.

계산과 관련된 여러 기능을 Calculator라는 클래스 안에 묶고 싶다면 정적 메서드를 사용할 수 있습니다.

Calculator.add(10, 20)
Calculator.multiply(10, 20)
Calculator.divide(10, 20)

이렇게 하면 해당 기능들이 계산과 관련된 기능이라는 것을 코드 구조만 봐도 알 수 있습니다.


어떤 메서드를 사용해야 할까?

처음에는 세 가지 중 무엇을 선택해야 할지 헷갈릴 수 있습니다.

다음과 같이 생각하면 비교적 간단합니다.

객체의 데이터를 사용해야 한다

def method(self):

인스턴스 메서드를 사용합니다.

예:

class Person:

    def introduce(self):
        print(self.name)

클래스의 데이터를 사용해야 한다

@classmethod
def method(cls):

클래스 메서드를 사용합니다.

예:

class Person:

    count = 0

    @classmethod
    def get_count(cls):
        return cls.count

객체나 클래스의 데이터가 필요하지 않다

@staticmethod
def method():

정적 메서드를 사용할 수 있습니다.

예:

class Calculator:

    @staticmethod
    def add(a, b):
        return a + b

즉 다음 세 가지 질문을 순서대로 생각해보면 됩니다.

이 메서드가 특정 객체의 데이터를 사용하는가?
        ↓
       Yes
        ↓
인스턴스 메서드

       No
        ↓
클래스의 데이터를 사용하는가?
        ↓
       Yes
        ↓
클래스 메서드

       No
        ↓
정적 메서드

마무리

Python 클래스의 메서드는 크게 인스턴스 메서드, 클래스 메서드, 정적 메서드로 나누어 볼 수 있습니다.

핵심적인 차이는 다음과 같습니다.

  • 인스턴스 메서드는 self를 통해 현재 객체의 데이터를 사용합니다.
  • 클래스 메서드는 @classmethod와 cls를 사용해 클래스와 관련된 작업을 수행합니다.
  • 정적 메서드는 @staticmethod를 사용하며 self나 cls가 필요하지 않습니다.
  • 클래스 메서드는 객체를 생성하는 대체 생성자로도 활용할 수 있습니다.
  • 정적 메서드는 특정 객체의 상태와 관계없는 기능을 클래스와 함께 묶을 때 사용할 수 있습니다.

특히 다음 세 가지를 기억해두면 좋습니다.

self → 현재 인스턴스
cls  → 현재 클래스
없음 → 인스턴스나 클래스 상태에 직접 의존하지 않음

다음 글에서는 클래스 내부에서 객체의 데이터가 실제로 어떻게 저장되는지 살펴보겠습니다. __dict__를 이용해 객체의 속성을 확인하는 방법과 함께, 메모리 사용을 줄이기 위해 사용할 수 있는 __slots__까지 비교해보겠습니다.

jiji

AI, Python, 생활정보와 정부 정책 정보를 쉽게 설명하는 정보 블로그입니다.

Ad Placeholder
Scroll to Top