서론
클래스 내에서 인스턴스 변수가 아닌 클래스 변수로 두었을 때 차이점과 언제 사용하는지에 대해 알아보겠다.
클래스 변수
class TreeNode:
val = 0
left = None
right = None
위 처럼 TreeNode라는 클래스가 있다고 가정해보자.
그 후에 인스턴스를 만들어 값을 변경해본다.
a = TreeNode()
b = TreeNode()
a.val = 1
print(b.val) # 0
TreeNode.val = 5
print(a.val) # 여전히 1 (인스턴스에서 덮어썼기 때문)
print(b.val) # 5 (공유 중인 클래스 변수의 변경을 반영)
a.val을 1로 바꾸어도 b.val이 0인 이유는 a.val = 1을 함으로써 인스턴스 변수로 덮어씌웠기 때문이다.
이번엔 클래스명으로 직접 접근을 하고 val을 변경하면 a.val은 인스턴스로 덮어씌웠기 때문에 변경되지 않지만 b의 경우에는 값이 변경되는 것을 볼 수 있다.
클래스 변수는 언제 사용할까?
클래스 변수는 모든 인스턴스가 공통으로 공유해야 할 때 사용한다.
class Car:
wheels = 4 # 모든 자동차는 바퀴가 4개
print(Car.wheels) # 4
c1 = Car()
c2 = Car()
print(c1.wheels, c2.wheels) # 4, 4
또는 아래처럼 구현하여 인스턴스 갯수를 셀 수 있다.
class User:
count = 0 # 클래스 전체에서 사용자 수 추적
def __init__(self, name):
self.name = name
User.count += 1
print(User.count) # 0
u1 = User("Alice")
u2 = User("Bob")
print(User.count) # 2
마지막으로는 공통자원 캐싱과 같은 역할로 사용가능하다.
class Database:
_connection_pool = []
@classmethod
def add_connection(cls, conn):
cls._connection_pool.append(conn)
클래스 메소드
클레스 메소드는 클래스명 자체를 인자로 받는 메소드이다.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
a = TreeNode()
인스턴스 메소드 같은경우 생성자 함수를 보면 self에 a라는 인스턴스 주소가 자동으로 입력되어지지만 클래스 메소드의 경우 클래스 명이 입력되어진다.
class Example:
count = 0
@classmethod
def show_class(cls):
print("cls is:", cls)
print("count is:", cls.count)
e = Example()
e.show_class()
"""
출력결과:
cls is: <class '__main__.Example'>
count is: 0
"""
Example().show_class()
"""
출력결과:
cls is: <class '__main__.Example'>
count is: 0
"""
이는 인스턴스를 만들어 접근하나, 클래스명으로 접근하나 같은결과가 보여진다.
클래스 메소드는 언제 사용할까?
클래스명으로 접근하는 클래스 변수에 접근할 때 사용한다
class Database:
_connection_pool = []
@classmethod
def add_connection(cls, conn):
cls._connection_pool.append(conn)
a = Database()
a.add_connection("hello")
Database().add_connection("world")
print(a._connection_pool) # ['hello', 'world']
Database()._connection_pool # ['hello', 'world']
클래스 기반으로 객체를 생성할 때도 사용한다.
class Animal:
def __init__(self, species):
self.species = species
@classmethod
def create(cls, animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
return cls("Unknown")
class Dog(Animal):
def __init__(self):
super().__init__("Dog")
class Cat(Animal):
def __init__(self):
super().__init__("Cat")
# 팩토리 메서드로 객체 생성
a1 = Animal.create("dog")
a2 = Animal.create("cat")
a3 = Animal.create("dragon")
print(a1.species) # Dog
print(a2.species) # Cat
print(a3.species) # Unknown
참고
스테틱 메소드와 햇갈릴 수도 있는데 이는 클래스의 어떠한 속성에도 변화를 일으키지 않는 함수로 입력이 들어오면 항상 같은 출력을 반환하는 함수들이 이에 해당된다. (클래스나 인스턴스에 의존하지 않는 함수)
class MathUtils:
@staticmethod
def add(a, b):
return a + b
print(MathUtils.add(3, 5)) # 8
Comment