![]()
참고자료
1️⃣ 클래스 설명
클래스는 하나의 템플릿이라고 생각하면 되는데, 템플릿 안에는 속성과 메서드가 존재한다. 속성과 메서드는 부품, 기능이라고 생각하면 된다.
그러면 나는 클래스를 불러와서 커스텀하고 실행시키게 되는데 그 때 이 객체(Object)를 인스턴스(Instance)라고 한다.
예를 들어 확인해보자.
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
def is_adult(self):
if self.age >= 19:
return "성인입니다"
else:
return "아직 아가에요"Person이라는 클래스는 name, age라는 속성과 성인인지 아닌지를 구분하는 is_adult()라는 메서드를 가지고 있다.
2️⃣ 클래스 속성 확인
가끔 새로운 라이브러리를 사용하려고 할 때, 이 클래스의 속성, 메서드가 알고 싶을 때가 있다. 라이브러리에서 제공하는 Documentation이나 help()를 통해 자세한 설명을 볼 수 있지만, 뭐가 있는지만 알고 싶을 때는 귀찮기도 하다.
그럴 때 dir() 함수를 이용하면 사전에 클래스 안에 어떤 속성, 메서드가 있는지 파악할 수 있다.
p = Person("Hong Gil-Dong", 14)
dir(p)
## Output
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'is_adult', 'name']3️⃣ 특별 메서드(Special Method)
위에서 dir()를 통해 클래스의 속성과 메서드들을 쉽게 파악할 수 있었다. 그런데 내가 만든 것보다 뭐가 많이 나온다.
Output에 보면 두 개의 밑줄(__메서드__)사이에 문자가 있는 메서드들이 많이 나열되어 있는데, 이들을 특별 메서드(special method) 또는 매직 메서드(magic method) 라고 부른다. 내가 정의하지 않아도 기본적으로 내장되어 있는 메서드로 사용자 정의할 수 있다고 한다.
몇 가지만 정리해두겠다.
| method | Description |
|---|---|
__init__(self, ...) | 객체가 생성될 때 초기화를 담당 |
__str__(self) | 객체를 문자열로 변환할 때 사용 |
__repr__(self) | 객체의 공식 문자열 표현을 제공. 디버깅할 때 사용 |
__len__(self) | 객체의 길이 정의. len() 함수 사용 |
__getitem__(self, key) | 인덱싱을 통해 항목을 접근할 때 사용. 예: obj[key] |
__setitem__(self, key, value) | 인덱싱을 통해 항목을 설정할 때 사용. 예: obj[key] = value |
__delitem__(self, key) | 인덱싱을 통해 항목을 삭제할 때 사용. 예: del obj[key] |
다음은 사용 예시이다.
Person클래스의 data메서드를 5일동안 몸무게를 체크한 기록이라고 하자.
class Person():
def __init__(self, name, age, data):
self.name = name
self.age = age
self.data = data
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
p = Person("Hong Gil-Dong", 14, [75, 76, 77, 78, 79])
p[2] = 80
print(p[0])
print(p.data)# Output
75
[75, 76, 80, 78, 79]
2️⃣ 데코레이터(Decorator)
쉽게 말하면 메서드를 속성처럼 쓸 수 있게 하는 것이다.
📋 @property
우리가 클래스에서 메서드를 만들고 실행할 때 object.method()처럼 ()를 함께 쓰게 되는데, 클래스를 만들다보면 메서드에 넣을 파라미터가 없는 경우들이 생긴다. 이럴 때에 쓰면 편하다.
위의 예제를 통해 살펴보면 쉽게 이해가 가능하다.
# @property 안쓴 경우
p = Person("Peter", 24)
print(p.is_adult()) # 어른입니다.
print(p.is_adult) # <bound method Person.is_adult of <__main__.Person object at 0x000001B1FDFC7E20>>
# @property 쓴 경우
p = Person("Peter", 24)
print(p.is_adult()) # TypeError: 'str' object is not callable
print(p.is_adult) # 어른입니다.@property.setter를 통해 인스턴스의 속성을 바꿀 수도 있다.
class Person():
def __init__(self, name, age, phone):
self.name = name
self.age = age
self.phone = phone
@property
def get_info(self):
return "/".join([self.name, str(self.age), self.phone])
@get_info.setter
def get_info(self, info):
name, age, phone = info.split("/")
self.name = name
self.age = age
self.phone = phonep = Person("John", 25, "010-1234-1234")
print(p.get_info)
p.get_info = "Peter/18/010-0987-6543"
print(p.name, p.age, p.phone)## Output
John/25/010-1234-1234
Peter 18 010-0987-6543
📋 @staticmethod
인스턴스의 속성에 의존하지 않는 메서드를 정의할 때 사용한다.
원래 메서드를 작성할 때 속성을 사용할 수 있도록 파라미터에 self도 작성하게 되는데 독립적인 함수를 만들때에도 써야해서 의미없을 때가 있다. 이럴 때 @staticmethod를 사용하는 것이다.
2024년을 기준으로 나이 계산기를 메서드로 만든다고 하자. 이때 속성을 사용하지 않고 태어난 년도 year의 파라미터만 받을 것이다.
class Person():
@staticmethod
def calculate_age(year):
return 2024 - year
# @staticmethod 안쓴 경우
p = Person()
print(p.calculate_age(2000)) # TypeError: Person.calculate_age() takes 1 positional argument but 2 were given
# @staticmethod 쓴 경우
p = Person()
print(p.calculate_age(2000)) # 24📋 @classmethod
보통 두 가지 목적으로 인해 사용한다.
- 클래스 자체의 속성이나 메서드를 조작할 때
- 대체 생성자(*인스턴스를 생성하는 또 다른 방법)를 제공할 때
@classmethod는 인스턴스의 속성이 아닌 클래스의 속성에 접근하기 때문에 self가 아닌 cls를 사용한다.
예시를 통해 이해하면 다음과 같다.
상황 설명
나는 다른 사람이 만든 Employee이라는 클래스를 사용하여 3개의 인스턴스(employee1, employee2, employee3)을 만들었다. 이 클래스에는 amount라는 연봉 인상률이라는 클래스 속성이 있다. 그리고 나는 이 3개의 인스턴스에 새로운 amount값을 적용하고 싶다.
@classmethod가 없다면?
employee1.amount = 1.04
employee2.amount = 1.04
employee3.amount = 1.04@classmethod가 있다면?
Employee.set_amount(1.04)위처럼 아주 간결하게 설정이 가능해진다.
그럼 이제 대체 생성자의 필요성에 대해 알아보자.
상황 설명
나는 사원증을 만드는 일을 한다. 이번에 신규 직원들의 사원증을 만들어야 하는데 그 수가 너무 많아 일일이 입력하기가 힘들다. 텍스트로 넣었을 때 적용되는 방법으로 바꾸면 좋겠지만, 원래의 방식도 존재했으면 좋겠다.
classmethod가 있다면?
employee1 = Employee("Jhon", "Sales Team", "과장")
employee2 = Employee.from_string("Jenny/R&D/"주임")
이렇게 다양한 버전으로 인스턴스를 간편하게 만들 수 있다.
위의 설명을 토대로 한 전체적인 코드는 다음과 같다.
class Employee():
amount = 1.02
def __init__(self, name, department, rank):
self.name = name
self.department = department
self.rank = rank
@classmethod
def set_amount(cls, amount):
cls.amount = amount
@classmethod
def from_string(cls, data):
name, department, rank = data.split("/")
return cls(name, department, rank)
if __name__ == "__main__":
person1 = Employee("Hong Gil-Dong", "Developer", "주임")
person2 = Employee("Kim Min soo", "Human Resources", "대리")
print(person1.amount)
print(person2.amount)
Employee.set_amount(1.05)
person1 = Employee("Hong Gil-Dong", "Developer", "주임")
person2 = Employee.from_string("Kim Min soo/Human Resources/대리")
print(person1.amount)
print(person2.amount)
## Output
1.02
1.02
1.05
1.05