본문 바로가기

프로그래밍/Python

[Python] staticmethod는 언제 사용해?

728x90
Python @staticmethod 실습 가이드
Python · @staticmethod

Python @staticmethod 실습 중심 가이드

이 글은 Python에서 자주 사용되는 @staticmethod를 인스턴스 메서드, 클래스 메서드와 비교하며 실습 중심으로 이해할 수 있도록 정리한 가이드입니다.

1. 메서드 3종류 큰 그림

Python 클래스 안에서 자주 만나는 메서드는 다음 세 가지입니다.

  • 인스턴스 메서드 (기본)
  • @classmethod가 붙은 클래스 메서드
  • @staticmethod가 붙은 정적 메서드
class Demo:
    def instance_method(self):
        print("인스턴스 메서드, self =", self)

    @classmethod
    def class_method(cls):
        print("클래스 메서드, cls =", cls)

    @staticmethod
    def static_method():
        print("정적 메서드, self/cls 없음")

obj = Demo()
obj.instance_method()
Demo.class_method()
Demo.static_method()
  • 인스턴스 메서드 → 개별 객체 상태(self)와 관련
  • 클래스 메서드 → 클래스 자체(cls)와 관련
  • 정적 메서드 → 인스턴스/클래스 상태와 무관한 “독립 함수”지만, 논리적으로 클래스와 묶고 싶을 때 사용

2. @staticmethod의 핵심 개념

@staticmethod
“클래스 안에 있지만, 인스턴스나 클래스 상태와 전혀 관계 없는 함수”를 정의할 때 사용합니다.

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

print(MathUtil.add(3, 5))

이 메서드는 self도, cls도 받지 않으며
MathUtil의 인스턴스를 만들지 않고도 바로 호출할 수 있습니다.

3. @staticmethod가 없을 때와 비교

만약 @staticmethod를 붙이지 않으면 어떻게 될까요?

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

MathUtil.add(3, 5)  # 문제 발생 가능

Python은 클래스 안의 함수를 “메서드”로 취급하고, 첫 번째 인자에 인스턴스나 클래스를 자동으로 바인딩하려 하기 때문에 의도와 다르게 동작하거나 에러를 유발할 수 있습니다.

@staticmethod는 “이 함수는 인스턴스/클래스 바인딩 없이 독립적으로 호출하겠다”라는 것을 Python에게 알려주는 역할을 합니다.

4. 동작 원리 – staticmethod() 함수

@staticmethod는 사실 데코레이터 문법을 쓴 표현입니다.

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

위 코드는 아래와 동등합니다.

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

    add = staticmethod(add)

staticmethod() 빌트인 함수가, 해당 함수를 “인스턴스/클래스에 바인딩하지 않는 정적 메서드”로 감싸 주는 역할을 합니다.

5. 실습 1 – 유틸 함수 모으기

문자열 관련 유틸리티를 StringUtil 클래스 안에 모아보겠습니다.

class StringUtil:
    @staticmethod
    def is_empty(s):
        return s is None or s == ""

    @staticmethod
    def to_upper(s):
        if s is None:
            return None
        return s.upper()

print(StringUtil.is_empty(""))
print(StringUtil.to_upper("hello"))

이 함수들은 인스턴스 상태와 무관하지만, “문자열 처리”라는 공통 주제 아래 클래스에 묶어두면 코드를 읽는 사람이 구조를 이해하기 쉬워집니다.

6. 실습 2 – 클래스와 연결된 계산 로직

원과 관련된 계산 로직을 Circle 클래스 내부에 정리해 봅니다.

import math

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return math.pi * self.radius ** 2

    @staticmethod
    def area_from_radius(r):
        return math.pi * r ** 2

c = Circle(3)
print(c.area())                 # 인스턴스 메서드
print(Circle.area_from_radius(3))  # 정적 메서드

area()는 인스턴스 상태(self.radius)를 사용하지만,
area_from_radius()는 단순히 반지름 값만 있으면 되므로 정적 메서드로 두는 것이 깔끔합니다.

7. 실습 3 – @classmethod와 비교

정적 메서드와 클래스 메서드는 자주 헷갈리므로, 간단한 예제로 비교해 봅니다.

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

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

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

p = Person.from_string("Alice,30")
print(p.name, p.age)
print(Person.is_adult(20))
print(Person.is_adult(15))
  • from_string새 인스턴스를 만들어 반환하므로 cls가 필요 → @classmethod
  • is_adult → 나이 숫자만 보고 판정, 인스턴스/클래스와 무관 → @staticmethod 적합

8. 실습 4 – 인스턴스로도 호출 가능한가?

class Demo:
    @staticmethod
    def hello():
        print("Hello from staticmethod")

d = Demo()
d.hello()        # 인스턴스로 호출
Demo.hello()     # 클래스로 호출

둘 다 호출이 가능합니다. 다만, 메서드 내부에서는 인스턴스(self)에 접근할 수 없으므로 보통은 Demo.hello()처럼 클래스를 통해 호출하는 스타일이 코드 가독성에 더 좋습니다.

9. 언제 @staticmethod를 쓰면 좋을까?

  • 인스턴스의 상태(self)와 관련이 없을 때
  • 클래스 자체(cls)에도 의존하지 않을 때
  • 그럼에도 불구하고 “이 함수는 이 클래스와 개념적으로 연결되어 있다”는 것을 표현하고 싶을 때

예시:

  • User 클래스 안의 hash_password(raw_password)
  • Order 클래스 안의 calculate_tax(price)
단, 모든 유틸 함수를 무조건 @staticmethod로 묶기보다는,
“이게 정말 이 클래스에 속하는 개념인가?”를 한 번 생각하고 사용하는 것이 좋습니다.

10. 연습 문제

연습 1 – 온도 변환기

TemperatureConverter 클래스를 만들고, 다음 정적 메서드를 구현해 보세요.

  • c_to_f(c): 섭씨 → 화씨
  • f_to_c(f): 화씨 → 섭씨

모든 메서드는 @staticmethod를 사용하고, 인스턴스를 만들지 않고 호출하도록 설계해 보세요.

연습 2 – 패스워드 유틸

PasswordUtil 클래스를 만들고:

  • @staticmethod is_strong(password) - 길이, 특수문자 포함 여부를 기준으로 강도 체크
  • 나중에 User 클래스에서 이 메서드를 활용
이런 연습을 통해,
“객체 상태와 무관한 로직을 클래스와 어떻게 구조적으로 묶을지”에 대한 감각이 생기게 됩니다.