클래스를 가장 잘 설명해주는 그림
클래스(class)란 똑같은 무엇인가를 계속해서 만들어 낼 수 있는 설계 도면(과자 틀)이고, 객체(object)란 클래스로 만든 피조물(과자 틀로 만든 과자)를 뜻함.
여기서 클래스로 만든 각 객체마다 고유한 성격을 가진다. 과자 틀로 만든 과자에 손상을 가해도 다른 과자에는 아무 영향이 없는 것과 마찬가지 !
class Cookie:
pass
a = Cookie()
b = Cookie()
위와 같이 1개의 클래스로 무수히 많은 객체를 만들어 낼 수 있다. Cookie()의 결괏값을 돌려받은 a와 b가 바로 객체이다.
객체와 인스턴스의 차이
클래스로 만든 객체를 인스턴스라 한다. a = Cookie()이렇게 만든 a는 객체이자, Cookie의 인스턴스이다. 즉 인스턴스라는 말은 특정 객체(a)가 어떤 클래스(Cookie)의 객체인지를 관계 위주로 설명할 때 사용한다.
isinstance(a, Cookie)
>>> True
dir(a)
>>> ['__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__',
'content',
'num',
'output']
FourCal()이라는 클래스를 사칙연산이 가능하도록 기능을 추가해야한다.
class FourCal:
pass
라는 껍질뿐인 class에 숫자를 지정할 수 있는 기능을 추가할 것이다.
class FourCal:
def setdata(self, first, second): #메서드의 매개변수
seld.first = first #메서드의 수행문
self.second = second #메서드의 수행문
클래스 안에 구현된 setdata함수는 다른 말로 메서드(method)라고 부른다. 메서드는 클래스에 포함되어 있다는 점 외에는 일반 함수와 다른 점이 없다.
setdata의 메서드는 매개변수로 self, first, second 3개의 입력값을 받는다. 이 중 일반 함수와는 달리 메서드의 첫번째 매개변수 self는 특별한 의미를 갖는다.
setdata 메서드에는 self, first, second 총 세개의 매개변수가 필요한데, 실제로는 a.setdata(4,2)
처럼 2개 값만 전달한다. 이유는 setdata의 첫번째 매개변수 self -> setdata 메서드를 호출한 객체 a가 자동으로 전달됨 ! (파이썬 메서드의 첫번째 매개변수 이름으로 관례적으로 self를 사용함. 객체 호출 시 호출한 객체 자신이 전달되기 때문 !)
메서드의 또 다른 호출 방법
a = FourCal() a.setdata(4,2)
객체(a) + 메서드(setdata) 형태로 호출 시 self 생략해서 호출
a = FourCal() FourCal.setdata(a,4,2)
클래스이름(FourCal) + 메서드(setdata) 형태로 호출 시 객체 a를 첫번째 매개변수 self에 꼭 전달 필요
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
def mul(self):
result = self.first * self.second
return result
def sub(self):
result = self.first - self.second
return result
def div(self):
result = self.first / self.second
return result
-> 더하기, 곱하기, 빼기, 나누기 등을 가능하게 메서드를 추가한 class
a = FourCal()
a.add()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in add
AttributeError: 'FourCal' object has no attribute 'first'
FourCal 클래스의 인스턴스 a에 setdata 메서드를 수행하지 않고 add 메서드를 먼저 수행하면, AttributeError: 'FourCal' object has no attribute 'first'
오류가 발생한다. 이는 setdata 메서드를 수행해야 객체 a의 객체변수 first와 second가 생성되기 때문
-> 이렇게 객체에 first, second와 같은 초깃값을 설정해야 할 필요가 있을때는 setdata와 같은 메서드를 호출해 초깃값을 설정하는 것 보다 생성자를 구현하는 것이 안전함 !
(생성자란 객체가 생성될 때 자동으로 호출되는 메서드)
def __init__(self, first, second):
self.first = first
self.second = second
메서드 이름을 setdata에서 __init__
로만 바꿔도 자동으로 생성자로 인식된다.
따라서 생성자를 활용한 class의 경우, 객체를 생성할때부터 first와 second에 해당되는 값을 전달하여야 한다.
a = FourCal()
-> a = FourCal(4,2)
기존 클래스에 기능을 수정하는 대신 왜 굳이 상속을 쓰냐 !
-> 기존 클래스가 라이브러리 형태로 제공되거나 수정이 허용되지 않는 상황이라면 상속을 활용해야 함
상속의 경우, 기존 클래스(FourCal)은 그대로 놔둔 채 클래스의 기능을 확장시킬 때 사용
class MoreFourCal(FourCal):
def pow(self):
result = self.first ** self.second
return result
a = FourCal(4,0)
a.div()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
result = self.first / self.second
ZeroDivisionError: division by zero
FourCal 클래스의 객체 a에 4와 0 값을 설정하고 div 메서드를 호출하면 분모가 0이기에 위와 같은 ZeroDivivionError 오류가 발생함. 하지만 0으로 나눌때 오류가 아닌 0을 리턴하고자 한다면 ?
-> FourCal 클래스를 상속하는 SafeFourCal 클래스를 생성
class SafeFourCal(FourCal):
def div(self):
if self.second == 0:
return 0
else:
return self.first / self.second
이런 식으로 부모 클래스(상속한 클래스)에 있는 메서드를 동일한 이름으로 다시 만드는 것을 메서드 오버라이딩(덮어쓰기)이라고 한다. 이렇게 메서드를 오버라이딩하면 SafeFoulCal(4,0) 수행 시 부모클래스의 메서드 대신 오버라이딩한 메서드가 호출된다 !
클래스 변수란 클래스 내, 함수 밖에서 변수명 = 데이터
형식으로 정의한 변수로서 클래스에서 생성한 모든 객체가 공통으로 사용
아래와 같이 클래스명.변수명
로 사용하거나, 객체를 생성한 후 객체(a).변수명
통해서도 클래스 변수를 접근 가능
class Family:
lastname = "김"
Family.lastname
>>> 김
a = Family()
a.lastname
>>> 김
self.변수명 = 데이터
형식으로 정의한 변수로 클래스 내의 모든 함수에서 self.변수명
으로 접근 가능 a.lastname = "최"(a 객체의 변수만 변경됨 -> 이게 인스턴스 변수)
a.lastname
>>>"최"
Family.lastname
>>>"박"
b.lastname
>>>"박"