클래스와 객체
과자를 만드는 과자 틀이 클래스(Class)이고, 과자 틀에 의해서 만들어진 과자가 객체(Object)
클래스는 무엇인가를 계속해서 만들어 낼 수 있는 설계 도면이고, 객체는 클래스로 만든 피조물을 뜻함
클래스로 만든 객체는 객체마다 고유한 성격을 가짐
과자 틀로 만든 과자에 구멍을 뚫거나 조금 베어 먹더라도 다른 과자에는 아무 영향이 없는 것과 마찬가지로
동일한 클래스에서 만든 객체들은 서로 영향을 전혀 주지 않음
class Cookie:
pass
위의 클래스는 아무 기능도 없는 껍질뿐인 클래스이지만, 껍질뿐인 클래스더라도 객체를 생성할 수는 있음
a = Cookie()
b = Cookie()
a와 b가 바로 객체
객체와 인스턴스의 차이
클래스로 만든 객체를 인스턴스(Instance)라고도 하는데
a = Cookie()로 객체를 생성했다면, a는 객체 / a 객체는 Cookie의 인스턴스
즉 인스턴스라는 말은 특정 객체(a)가 어떤 클래스(Cookie)의 객체인지를 관계 위주로 설명할 때 사용
"a는 인스턴스" 보다는 "a는 객체"라는 표현이 어울리고, "a는 Cookie의 객체" 보다는 "a는 Cookie의 인스턴스"라는 표현이 어울림
사칙연산 클래스 만들기
클래스를 어떻게 만들지 먼저 구상하기
클래스로 만든 객체를 중심으로 어떤 식으로 동작하게 할 것인지 미리 구상을 한 후에 생각한 것들을 하나씩 해결하면서 완성해 나가야함
사칙연산을 가능하게 하는 FourCal 클래스가 다음처럼 동작한다고 가정
a = FourCal() # FourCal 클래스로 a라는 객체 생성
a.setdata(4, 2) # 4와 2를 a에 지정
print(a.add()) # add()를 수행하면 두 수를 합한 결과를 출력
print(a.sub()) # sub()를 수행하면 두 수를 뺀 결과를 출력
print(a.mul()) # mul()를 수행하면 두 수를 곱한 결과를 출력
print(a.div()) # div()를 수행하면 두 수를 나눈 결과를 출력
이렇게 동작하는 FourCal 클래스를 만드는 것이 목표
메서드
메서드 (Method) : 클래스 안에 구현된 함수
클래스 구조 만들고, 객체에 숫자 지정할 수 있게 만들기
class FourCal:
def setdata(self, first, second): # setdata() 메서드
self.first = first
self.second = second
메서드의 첫번째 매개변수 self
setdata 메서드는 self, first, second 3개의 매개변수를 받는데
일반적인 함수와 다르게 메서드의 첫번째 매개변수 self는 특별한 의미를 가짐
a = FourCal()
a.setdata(4, 2)
이상하게도 setdata 메서드에는 3개의 매개변수가 필요한데, 실제로는 a.setdata(4, 2)처럼 2개의 매개변수만 전달함
Why? a.setdata(4, 2)처럼 호출하면 setdata 메서드의 첫번째 매개변수 self에는 setdata메서드를 호출한 객체 a가 자동으로 전달됨
파이썬 메서드의 첫번째 매개변수 이름은 관례적으로 self를 사용함
객체를 호출할 때 호출한 객체 자신이 전달되기 때문에 self를 사용한 것이지만 다른 이름을 사용해도 상관은 없음
✔️ Java 같은 언어는 첫번째 매개변수 self가 필요없지만, Python은 첫번째 매개변수 self를 명시적으로 구현함
객체변수
객체변수 : 객체에 생성되는 객체만의 변수
a.setdata(4, 2) 처럼 호출하면 a객체에 객체변수 first가 생성되고 값 4가 저장됨
a = FourCal()
b = FourCal()
a.setdata(4, 2)
b.setdata(3, 7)
print(a.first)
print(b.first)
4 # print(a.first)의 결과
3 # print(b.first)의 결과
a객체의 first값은 b객체의 first값에 영향을 받지 않고, 원래의 값을 유지하고 있음
클래스로 만든 객체의 객체변수는 다른 객체의 객체변수와 상관없이 독립적인 값을 유지함
사칙연산 구현
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
def sub(self):
result = self.first - self.second
return result
def mul(self):
result = self.first * self.second
return result
def div(self):
result = self.first / self.second
return result
a = FourCal()
b = FourCal()
a.setdata(4, 2)
b.setdata(3, 7)
print(a.add())
print(a.sub())
print(a.mul())
print(a.div())
print(b.add())
print(b.sub())
print(b.mul())
print(b.div())
6
2
8
2.0
10
-4
21
0.42857142857142855
생성자
class FourCal:
def setdata(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
a = FourCal()
a.add()
FourCal 클래스의 인스턴스 a에 setdata 메서드를 수행하지 않고 add 메서드를 수행하면
"'FourCal' object has no attribute 'first'" 오류가 발생함
setdata 메서드를 수행해야 객체 a의 객체변수 first와 second가 생성되기 때문
이렇게 객체에 초기값을 설정해야 할 필요가 있을 때는 setdata와 같은 메서드를 호출하여 초기값을 설정하기보다
생성자를 이용하여 구현하는 것이 안전함
생성자 (Constructor) : 객체가 생성될 때 자동으로 호출되는 메서드; __init__
위의 예제에서 setdata 메서드 대신 __init__ 으로 생성자를 만듦
class FourCal:
def __init__(self, first, second):
self.first = first
self.second = second
def add(self):
result = self.first + self.second
return result
a = FourCal()
a = FourCal() 을 수행할 때 생성자 __init__ 이 호출되어
"__init__() missing 2 required positional arguments: 'first' and 'second'" 라는 오류가 발생
오류가 발생한 이유는 생성자의 매개변수 first와 second에 해당하는 값이 전달되지 않았기 때문
a = FourCal(4, 2)
이처럼 first와 second에 해당하는 값을 전달하여 객체를 생성해야 함
클래스의 상속
'상속'이란 말 그대로, 어떤 클래스를 만들 때 다른 클래스의 기능을 물려받을 수 있게 만드는 것
클래스를 상속하기 위해서는 클래스 이름 뒤 괄호 안에 상속할 클래스의 이름을 넣어주면 됨
기존 클래스를 변경하지 않고, 기능을 추가하거나 기존 기능을 변경하려고 할 때 사용
앞에서 FourCal 클래스는 이미 만들었으므로, FourCal 클래스를 상속하는 MoreFourCal 클래스를 만듦
class MoreFourCal(FourCal): # FourCal 클래스를 상속
def pow(self): # 제곱
result = self.first ** self.second
return result
c = MoreFourCal(4, 2)
print(c.second)
print(c.add()) # FourCal 클래스의 기능
print(c.pow()) # MoreFourCal 클래스에 만든 기능
2 # print(c.second)의 결과
6 # print(c.add())의 결과
16 # print(c.pow())의 결과
MoreFourCal 클래스는 FourCal 클래스를 상속했으므로 FourCal 클래스의 모든 기능을 사용할 수 있고, 기능을 확장할 수 있음
메서드 오버라이딩
메서드 오버라이딩 (Method Overriding, 덮어쓰기) : 상위 클래스에 있는 메서드를 동일한 이름으로 다시 만드는 것
d = FourCal(4, 0)
d.div()
FourCal 클래스의 객체 d에 객체변수로 4와 0을 설정하고 div 메서드를 호출하면 4를 0으로 나누려고 하기 때문에
"division by zero" 오류가 발생함, 0으로 나눌 때 오류가 아니라 0을 돌려주도록 만들고 싶다면?
class SafeFourCal(FourCal):
def div(self):
if self.second == 0:
return 0
else :
return self.first / self.second
d = SafeFourCal(4, 0)
print(d.div())
0 # print(d.div())의 결과
클래스변수
클래스변수 : 클래스에 생성되는 클래스만의 변수
class Family:
lastname = '김'
print(Family.lastname)
김 # print(Family.lastname)의 결과
'클래스이름.클래스변수' 로 사용할 수 있음
e = Family()
f = Family()
print(e.lastname)
print(f.lastname)
김 # print(e.lastname)의 결과
김 # print(f.lastname)의 결과
클래스로 만든 객체를 통해서도 클래스변수를 사용할 수 있음
class Family:
lastname = '이'
e = Family()
f = Family()
print(e.lastname)
print(f.lastname)
이 # print(e.lastname)의 결과
이 # print(f.lastname)의 결과
클래스변수 값을 변경했더니 클래스로 만든 객체의 객체변수 값도 모두 변경됨
클래스변수는 클래스로 만든 모든 객체에 공유됨
📝 참고
'Programming > Python' 카테고리의 다른 글
[Python] py ipynb 변환 (Jupyter Notebook 이용) (0) | 2022.04.12 |
---|---|
Python JSON 파일(.json) 저장 및 불러오기 (0) | 2022.03.03 |
Python Numpy Tutorial (with Jupyter and Colab) (0) | 2022.02.15 |
[Python] 객체지향 - super() (0) | 2021.11.15 |
Python 지역변수, 전역변수 (0) | 2021.11.11 |