클래스
- 클래스는 관련된 속성과 동작을 하나의 범주로 묶어 실세계의 사물을 흉내 낸다.
왜 사용하는가?
-
계좌를 떠올려 보자. 계좌에는 잔액이 있고 입출금 및 조회라는 행위가 존재한다.
-
계좌를 이용하고 싶은데 입금을 하려면 A라는 곳으로 가야하는데 잔액 조회를 하려면
B라는 곳으로 가야한다면 얼마나 불편할까
-
이를 한 번에 묶어서 계좌를 만드는 순간 입출금, 잔액조회를 한 장소에서 할 수 있게 해주는 것이 클래스이다
생성자
- num = 5와 같이
integer
변수를 초기화 하는 것은 매우 간단하다. - 그런데 아까 같이 계좌를 떠올리면 어떤가? 계좌에는 정말 많은 정보(멤버)가 존재한다
- 계좌번호, 잔액, 은행, 거래내역…
- num을 초기화 할 때처럼 일일이 넣는다면 코드가 비효율적으로 늘어날 것이다.
- 이를 효율적으로 해결해주는 게 생성자이다.
class Class이름:
def __init__(self, 초기값):
멤버 초기화
메서드 정의
객체1 = Class이름(맴버1, 맴버2, 맴버3, ...)
객체2 = Class이름(맴버1, 맴버2, 맴버3, ...)
- 생성자는 이처럼 새로운 객체를 만들 때 불린다.
- 편하게 붕어빵을 찍어낸다 생각하면 될 것이다.
상속
-
기존에 만든 클래스(부모)에 몇 가지 기능을 추가하여 새로운 클래스(자식)를 만들고 싶을 때 사용한다.
-
내가 새로 만든 클래스의 모든 기능을 다시 다 작성하지 않고 부모클래스의 기능을 가져올 수 있다는 점은
매우 매력적인 기능임을 사용하다 보면 느끼게 될 것이다.
-
그렇다고 부모의 기능을 무조건 사용해야 하는 것은 아니다. 자식 클래스에 맞게 부모의 함수를 바꾸는 Override라는 기능도 있다.
-
앞으로 많이 볼테니 예시 코드는 생략 >_O
액세서
- 클래스에 있는 멤버를 일정한 규칙으로 접근하게 하는 메서드로
Getter
와Setter
가 있다. - 아까 계좌를 떠올려보자. 계좌의 멤버에 아무렇게나 변경할 수 있게 한다면 실수로 잔액이 -50000원이 될 지도 모르는일 아닌가?
- 말로만 설명하는 것보다 직접 살펴보는 편이 이해가 더 잘 될 것이다.
class Date:
def __init__(self, month):
self.__month = month;
@property
def month(self):
return self.__month
@month.setter
def month(self, month):
if 1 <= month <= 12:
self.__month = month
today = Date(8)
today.month = 15
print(today.month)
@property
는Getter
의 decorator이고@이름.setter
는Setter
의 decorator이다.- 위와 같이
Getter
와Setter
를 사용하면 15월달이 새로 생기는 불상사는 일어나지 않을 것이다.
클래스 메서드
- 여태까지 사용했던 함수들은 다 객체별로 따로 동작하였다.
- 그런데 모든 객체가 공유할 수 있는 함수 혹은 변수가 있으면 유용하지 않을까?(
그냥 그렇다고 하자) - 그런 당신의 의문을 위해 준비했다. 바로 클래스 메서드이다.
class Car:
count = 0
def __init__(self, name):
self.name = name
Car.count += 1
@classmethod
def outcount(cls):
print(cls.count)
pride = Car("프라이드")
korando = Car("코란도")
Car.outcount()
-
@classmethod
는 클래스 메서드의 decorator이다. -
새로운 Car객체가 생길 때마다 클래스 전체에 공유되는 변수 count가 1씩 증가하게 되고
최종적으로 Car.outcount()함수를 부르면 여태까지 생긴 Car객체의 개수가 출력되게 된다.
정적 메서드
- 정적메서드는 클래스에 포함되는 단순한 유틸리티 메서드이다.
- 특정 객체에 소속되지 않고 클래스와 관련된 동작을 하지도 않는다(?)
class Car:
count = 0
def __init__(self, name):
self.name = name
Car.count += 1
@classmethod
def outcount(cls):
print(cls.count)
@staticmethod
def hello():
print("오늘도 안전운전하세요")
Car.hello()
@staticmethod
는 정적메소드의 decorator이다.- 말 그대로 그냥 클래스에 포함되어 있을뿐인 함수이다.
연산자 메서드
-
우리는 if문에서 !=라든지 >=같은 비교연산자를 변수 사이에서 +나 //같은 연산자를 자주 사용했었다.
그런데 객체 간에 이러한 연산자를 사용하고 싶으면 어떨까?
-
눈치 빠른 사람이라면 바로 연산자 오버로드를 떠올릴 것이다. 그런데
C++
에서는 자주 했었는데Python
은 연산자를 함수의 이름으로 쓸 수 없다고 한다.ㅜ_ㅜ 그래서 준비했다~
연산자 | 메서드 |
---|---|
== | _ _ eq _ _ |
!= | _ _ ne _ _ |
< | _ _ lt _ _ |
> | _ _ gt _ _ |
<= | _ _ le _ _ |
>= | _ _ ge _ _ |
+ | _ _ add _ _ |
- | _ _ sub _ _ |
* | _ _ mul _ _ |
/ | _ _ div _ _ |
// | _ _ floordiv _ _ |
% | _ _ mod _ _ |
** | _ _ pow _ _ |
_ _ eq _ _
class Human:
def __init__(self, age, name):
self.age = age
self.name = name
def __eq__(self, other):
return self.age == other.age and self.name == other.name
kim = Human(29, "김상형")
sang = Human(29, "김상형")
moon = Human(44, "문종민")
print(kim == sang)
print(kim == moon)
print(kim is sang)
# ==> True False False
- 우리가 원하는대로 나오는 것을 볼 수 있다.
- 여기서 한 가지 재밌는 점은
is
연산자를 사용했을 때False
가 나온다는 점이다. 정답은 생성자에 있다.
특수 메서드
- 지금까지 기본적으로 사용되는 메서드를 배웠다고 하면 이제부터는 조금 심화버전의 메서드가 나온다.
- 크게 str, repr, len 3가지를 볼 것이다. 설명과 예시를 보자.
메서드 | 설명 |
---|---|
_ _ str _ _ | str(객체) 형식으로 객체를 문자열화한다. |
_ _ repr _ _ | repr(객체) 형식으로 객체의 표현식을 만든다. |
_ _ len _ _ | len(객체) 형식으로 객체의 길이를 조사한다. |
_ _ str _ _
class Human:
def __init__(self, age, name):
self.age = age
self.name = name
def __str__(self):
return "이름 %s, 나이 %d" %(self.name, self.age)
kim = Human(29, "김상형")
print(kim)
# __str__의 유무
# <__main__.Human object at 0x000002744AAD3588> => 이름 김상형, 나이 29
_ _ repr _ _
class Human:
def __init__(self, age, name):
self.age = age
self.name = name
def __str__(self):
return "이름 %s, 나이 %d" % (self.name, self.age)
def __repr__(self):
return "Human(" + str(self.age) + ",'" + self.name + "')"
kim = Human(29, "김상형")
print(kim)
kimexp = repr(kim)
kimcopy = eval(kimexp)
print(kimcopy)
- 이 기능을 잘 사용하면 객체를 표현식으로 바꾸고 다시 표현식으로부터 객체를 만드는 등의 방식으로 활용할 수 있다.
_ _ len _ _
class Card:
spade = []
heart = []
clover = []
diamond = []
def __init__(self, spade, heart, clover, diamond):
self.spade.extend(spade)
self.heart.extend(heart)
self.clover.extend(clover)
self.diamond.extend(diamond)
def __len__(self):
return len(self.spade) + len(self.heart) + len(self.clover) + len(self.diamond)
card = Card([0,1,2,3],[3,4,5,6],[1,2,7,'J'],['Q','K'])
print(len(card))