[PyTorch로 시작하는 딥러닝 입문] 2장 파이토치 기초 (3)_Class
안녕하세요. 한 달만에 글을 쓰네요. 여러가지로 많이 바빴습니다… 😅 특히 9월에 너무나두요… ㅎㅎ 10월의 첫 포스트로 이번 시간에는 파이토치 기초 2장 마지막 내용으로 파이썬 클래스를 소개드리겠습니다. 아직도 제가 많이 어려워하는 파트지만 아주아주 중요한 부분입니다!
2-4. 파이썬 클래스(Class)
1. 클래스란?
우선 클래스가 왜 필요한지부터 알아보죠! 저는 임의의 수를 입력하면 누적하여 덧셈한 결과가 나오는 함수를 만들었습니다.
result = 0
def add(num) :
global result
result += num
return result
print(add(10))
print(add(20))
--------------------------------------------------------------------------------------------------------------------------------
10
30
위의 함수는 문제없이 잘 작동합니다. 그런데 만약 한 프로그램에서 3개의 각기 다른 누적 덧셈 결과가 동시에 나와야 한다면 어떻게 해야 할까요? 함수 하나로는 각각의 누적 덧셈 결과값을 저장하기 힘들 것입니다. 따라서 함수 3개가 필요할 것이며, 아래와 같이 만들 수 있습니다.
result1 = 0
result2 = 0
result3 = 0
def add1(num) :
global result1
result1 += num
return result1
def add2(num) :
global result2
result2 += num
return result2
def add3(num) :
global result3
result3 += num
return result3
print(add1(10))
print(add1(20))
print('')
print(add2(30))
print(add2(40))
print('')
print(add3(50))
print(add3(60))
--------------------------------------------------------------------------------------------------------------------------------
10
30
30
70
50
110
이제는 누적 덧셈 결과가 4개 이상이라고 생각해보죠. 그렇다면 함수도 4개 이상이 필요할 것입니다. 이는 상당히 비효율적인 방법입니다. 이럴 경우에 유용하게 사용할 수 있는 것이 바로 클래스(Class)입니다. 쉽게 말해 클래스는 붕어빵을 만들기 위한 붕어빵 틀이라고 생각하면 쉽습니다. 만들어야 하는 붕어빵이 무수히 늘어나더라도 붕어빵 틀 하나만 있다면 계속 만들 수 있으니까요. 클래스를 이용한 누적 덧셈 코드는 뒤에서 다시 한 번 설명드리겠습니다.
2. self
그렇다면 클래스가 코딩에서 어떻게 사용되는지 자세히 설명드리고자 새로운 예시를 들도록 하겠습니다. 서비스 회사 W는 두 수를 입력하면 그 수들의 덧셈 결과를 출력해주는 서비스를 아래와 같이 개발했습니다.
class Service :
def sum(self, a, b) : # 더하기 서비스
result = a + b
print(f"{a} + {b} = {result} 입니다.")
그래서 Andy Warhol은 업체 W에 가입을 하여 아이디를 받았고, 더하기 서비스를 이용했습니다. 아래에서 Andy라는 객체는 Service의 인스턴스입니다.
Andy = Service() # 서비스 업체에 가입해서 아이디를 받는다.
Andy.sum(3, 4) # 더하기 서비스를 이용한다.
--------------------------------------------------------------------------------------------------------------------------------
3 + 4 = 7 입니다.
W는 오직 서비스에 가입한 사람들에게만 더하기 서비스를 제공하고 싶었습니다. 그래서 Service 클래스의 sum 함수를 보면 self라는 변수가 들어가져 있습니다. Andy.sum(3, 4)를 하게 되면, Andy가 서비스 가입자인지 먼저 확인을 하고 나서 서비스를 제공합니다. 따라서 원래는 Andy.sum(Andy, 3, 4)으로 써야 맞습니다. 그런데 Andy.sum(3, 4)을 했을 때, self는 호출 시 사용했던 인스턴스인 Andy로 바뀌기 때문에 Andy.sum(3, 4)으로 코드를 작성해도 무방합니다. 참고로 말씀드리자면, 클래스 안의 함수의 첫 번째로 사용되는 인수는 무조건 self로 사용해야 인스턴스의 함수로 사용이 가능합니다.
3. 생성자 : __init__
이제 W 업체는 이름도 출력해주는 서비스를 개발했습니다.
class Service :
def setname(self, name) :
self.name = name
def sum(self, a, b) : # 더하기 서비스
result = a + b
print(f"{self.name}님 {a} + {b} = {result} 입니다.")
그리고 가입자인 Andy Warhol은 아래와 같이 서비스를 이용했습니다.
Andy = Service()
Andy.setname('Andy Warhol')
Andy.sum(3, 4)
--------------------------------------------------------------------------------------------------------------------------------
Andy Warhol님 3 + 4 = 7 입니다.
위의 서비스는 아주 유용하게 사용할 수 있지만, 큰 단점이 존재합니다. 어떤 사용자가 Fool이라는 아이디로 서비스를 가입했습니다. 이 상태에서 바로 덧셈 서비스를 이용하려고 하면 오류가 발생합니다. 이름을 넣어 주는 과정이 빠졌기 때문인데, 이 문제를 해결하기 위해 처음에 가입할 때 반드시 이름을 기입해야만 서비스를 받을 수 있게 클래스를 수정합니다.
Fool = Service()
Fool.sum(1, 2)
--------------------------------------------------------------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-13-27a62e122639> in <cell line: 2>()
1 Fool = Service()
----> 2 Fool.sum(1, 2)
<ipython-input-12-6bbcf5f649bd> in sum(self, a, b)
9 def sum(self, a, b) : # 더하기 서비스
10 result = a + b
---> 11 print("%s님 %s + %s = %s 입니다." % (self.name, a, b, result))
AttributeError: 'Service' object has no attribute 'name'
class Service :
def __init__(self, name) :
self.name = name
def sum(self, a, b) : # 더하기 서비스
result = a + b
print(f"{self.name}님 {a} + {b} = {result} 입니다.")
클래스에서 __init__라는 생성자 함수는 인스턴스를 만들 때 항상 실행된다는 특별한 의미를 갖습니다. 즉, 아이디를 부여받을 때 항상 실행된다는 말로, name이 인자로 있기 때문에 가입 시 꼭 이름이 입력되어야 합니다. Andy = Service()로 입력할 경우, 오류가 발생합니다.
Andy = Service('Andy Warhol')
Andy.sum(3, 4)
--------------------------------------------------------------------------------------------------------------------------------
Andy Warhol님 3 + 4 = 7 입니다.
그렇다면 다시 1번 파트로 넘어가서 처음에 만들고자 했던 누적 덧셈 클래스를 만들어 봅시다. 초기값을 0으로 하여 객체를 세 개 생성했을 때, 누적합을 아래와 같이 손쉽게 구할 수 있습니다. 세 객체 모두 서로 독립적으로 연산됨을 알 수 있습니다.
class Calculator :
def __init__(self) :
self.result = 0
def add(self, num) :
self.result += num
return self.result
cal1 = Calculator()
cal2 = Calculator()
cal3 = Calculator()
print(cal1.add(10))
print(cal1.add(20))
print('')
print(cal2.add(30))
print(cal2.add(40))
print('')
print(cal3.add(50))
print(cal3.add(60))
--------------------------------------------------------------------------------------------------------------------------------
10
30
30
70
50
110
4. 클래스의 응용
W 업체에서 더하기 뿐 아니라, 빼기, 곱하기, 나누기 서비스도 새로 개시했습니다. 지금까지의 내용들을 응용하여 아래와 같이 코드를 생성할 수 있습니다.
class Service :
def __init__(self, name) :
self.name = name
def sum(self, a, b) : # 더하기 서비스
result = a + b
print(f"{self.name}님 {a} + {b} = {result} 입니다.")
def sub(self, a, b) : # 빼기 서비스
result = a - b
print(f"{self.name}님 {a} - {b} = {result} 입니다.")
def mul(self, a, b) : # 곱하기 서비스
result = a * b
print(f"{self.name}님 {a} * {b} = {result} 입니다.")
def div(self, a, b) : # 나누기 서비스
result = a / b
print(f"{self.name}님 {a} / {b} = {result} 입니다.")
Andy = Service('Andy Warhol')
Andy.sum(3, 4)
Andy.sub(10, 2)
Andy.mul(7, 8)
Andy.div(90, 5)
--------------------------------------------------------------------------------------------------------------------------------
Andy Warhol님 3 + 4 = 7 입니다.
Andy Warhol님 10 - 2 = 8 입니다.
Andy Warhol님 7 * 8 = 56 입니다.
Andy Warhol님 90 / 5 = 18.0 입니다.
5. 상속
어떤 클래스를 만들 때, 다른 클래스의 기능을 물려받는 것을 말합니다. 예를 들어 ‘신씨네 집’이라는 클래스를 만들어 보겠습니다. __init__를 통해 이름을 기입하고, travel 함수에서 나라를 입력했을 때, 아래와 같은 글귀가 출력됩니다.
class HouseShin :
lastname = "신"
def __init__(self, name) :
self.fullname = self.lastname + name
def travel(self, where) :
print(f'{self.fullname}, {where}여행을 가다')
singer1 = HouseShin("용재")
singer1.travel("미국")
--------------------------------------------------------------------------------------------------------------------------------
신용재, 미국여행을 가다
여기에서 새로운 클래스인 HouseKim을 만듭니다. 성을 “김”으로 바꾸고, class 생성 시, HouseKim 괄호 안에 HouseShin을 넣은 것 외에는 추가된 것이 없습니다. 그럼에도 불구하고, HouseShin과 같은 기능을 갖는 것을 알 수 있습니다. 이와 같이 상속 기능을 이용하면 기존의 클래스와 동일한 기능을 가지는 새로운 클래스를 편리하게 만들 수 있습니다.
class HouseKim(HouseShin) :
lastname = "김"
singer2 = HouseKim("동률")
singer2.travel("일본")
--------------------------------------------------------------------------------------------------------------------------------
김동률, 일본여행을 가다
추가적으로 메서드 오버라이딩에 대해서 설명드립니다. 상속받는 클래스의 함수 이름은 동일하게 가져오되, 내용을 살짝 수정하여 다시 구현하는 것을 말합니다. 예를 들어, HouseShin 클래스에서 글귀를 출력할 때, 여행 기간도 같이 출력되게 하고 싶습니다. 그럴 때, 아래와 같이 내용을 수정하여 구현할 수 있습니다.
class HouseKim(HouseShin) :
lastname = "김"
def travel(self, where, day) :
print(f"{self.fullname}, {where}여행 {day}일 가네")
singer3 = HouseKim("동률")
singer3.travel("중국", 7)
--------------------------------------------------------------------------------------------------------------------------------
김동률, 중국여행 7일 가네
6. 연산자 오버로딩
연산자를 객체끼리 사용할 수 있게 하는 기법입니다. 예를 들어, HousePark의 객체끼리 덧셈 기호를 사용하여 결혼이라는 새로운 결과를 도출하게 할 수 있습니다. __add__는 ‘+’를 객체에 사용했을 때 호출되는 함수이며, __sub__는 ‘-‘를 객체에 사용했을 때 호출되는 함수입니다.
class HousePark :
lastname = "박"
def __init__(self, name) :
self.fullname = self.lastname + name
def travel(self, where) :
print(f'{self.fullname}, {where}여행을 가다')
def love(self, other) :
print(f"{self.fullname}, {other.fullname} 사랑에 빠졌네")
def __add__(self, other) : # <- 연산자 오버로딩 사용, '+'를 객체에 사용하게 되면 HousePark 클래스의 __add__라는 함수가 호출된다.
print(f"{self.fullname}, {other.fullname} 커플이 되었네")
def fight(self, other) :
print(f"{self.fullname}, {other.fullname} 싸우네")
def __sub__(self, other) : # <- 연산자 오버로딩 사용, '-'를 객체에 사용하게 되면 HousePark 클래스의 __sub__라는 함수가 호출된다.
print(f"{self.fullname}, {other.fullname} 헤어졌네")
class HouseChoi(HousePark) :
lastname = "최"
def travel(self, where, day) :
print(f"{self.fullname}, {where}여행 {day}일 가네")
man = HousePark("몽룡")
woman = HouseChoi("춘향")
man.love(woman)
man + woman
--------------------------------------------------------------------------------------------------------------------------------
박몽룡, 최춘향 사랑에 빠졌네
박몽룡, 최춘향 커플이 되었네
man.fight(woman)
man - woman
--------------------------------------------------------------------------------------------------------------------------------
박몽룡, 최춘향 싸우네
박몽룡, 최춘향 헤어졌네
댓글남기기