함수란 프로그램의 중복을 막기 위한 모듈이고 이 모듈의 호출을 통해 간편하게 짜놓은 로직에 각기 다른 input값을 넣고, 프로그램을 반복적으로 실행시킬 수 있다.
a=1
b=2
result = a+b
위와 같은 덧셈 프로그램이 아닌, 아래의 함수를 통해
def add(a,b):
result = a+b
return result
input값을 자유롭게 바꿔가며 재사용할 수 있는 reusable한 덧셈 프로그램을 짜는 것이다. 반복을 피하는게 프로그래밍의 목적 아닌가.
그렇다면 클래스는 왜 사용을 할까? C언어에는 클래스가 없다는데... 그리고 실상은 클래스 없이들 코딩들 많이 하던데... 라는 의문을 가지기 쉽다. 물론, 클래스가 없어도 된다. 심지어 함수가 없어도 된다. if, while, for 문만 있으면 대부분의 문제를 해결하고 코딩을 해낼 수 있다. 다만, 우리는 언제나 효율성이라는 측면에 주목해야 한다. 그 개념이 어렵다 할지라도 더 나은 방식을 위해서라면 이해하려고 노력해야 한다.
클래스는 함수와 마찬가지로 재사용이 가능한 모듈인데, 여러 변수와 여러 함수의 묶음이다. 함수와의 가장 큰 차이는 단일 함수가 아니라 여러 함수가 들어있을 수 있고, 무엇보다 변수가 리셋되지 않고 저장된다는 것이다. 함수에서는 아래와 같이 코딩을 하면
def add(a,b):
result = a+b
return result
result가 함수가 새로이 호출 될 때마다 리셋이 되버리고 만다.
그러면 아래와 같이 코딩하면 계속해서 더해 갈수 있는것 아냐? 라고 할수도 있다.
def add(a,b):
result = result + a+b
return result
해보시면 알겠지만, result+a+b의 result 부분에서 에러가 발생한다. result가 정의되지 않았다는 것이다. 만약 함수 안에 result=0을 선언하면 결국은 호출때마다 계속 리셋이 되는 프로그램이 되고 말고, 함수 바깥에 result=0을 선언한다 하더라도, 함수에서는 마찬가지 정의되지 않았다는 에러가 발생한다.
함수내의 result 변수는 지역변수이고, 함수밖의 result는 전역변수로 서로 다른변수이기 때문이다. 전역변수는 메모리의 데이터영역에 주소를 갖고 저장되는 변수이고, 지역변수는 stack 영역에 주소를 갖고 있기에 서로 이름만 같을뿐, 별개의 변수가 되어 버린다. stack영역의 변수는 함수가 종료되면 모두 휘발되는 특성을 갖고 있기에 변수값이 함수가 호출 될 때마다 리셋 되어버리는 현상이 발생하는 것이다.
그렇다면 클래스에서는 1)어떻게 변수가 리셋이 안되는 것일까? 그리고 2)왜 변수가 리셋이 안되도록 한 것일까?
1)정확히 말하자면 클래스가 만들어낸 인스턴스의 변수값이 리셋이 되지 않고 저장된다는 것이다.
class Calculator:
def __init__(self):
self.result = 0
def add(self, first, second):
result = self.result + self.first + self.second
return result
이렇게 만들어진 클래스를 통해 붕어빵기계에서 붕어빵을 찍듯이,
cal1 = Calculator()
cal1.add(10,20)
cal1.add(30,20)
이렇게 cal1이라는 인스턴스가 만들어졌고, 이 인스턴스는 self.result를 통해 cal1.result 라는 고유의 변수명을 부여받게 된다. 이 변수는 함수에서의 변수와는 다르게 heap 메모리영역이라는 휘발되지 않는 공간에 저장되어, add를 여러번 할때마다 이전에 저장된 cal1.result라는 값을 다시 불러와서 값이 누적되어 계산 될 수 있도록 하는 것이다.
2)이렇게 인스턴스 변수를 통해 값을 저장함으로서 해당 변수에 값을 더하기도 하고 빼기도 하면서 변화를 줄수가 있다. 이렇게 하는 이유가 뭘까? 그 이유는 프로그램을 짜다 보면 그러한 필요와 수요가 있기 때문이다. 당연하지 않겠는가? 예를 들어보자.
키움에서 만든 주식매매 프로그램이 있다고 생각하자. 주식매매Class가 있다고 생각해보자. 이 클래스를 이용해 나만의 인스턴스(객체)를 만들어 앞으로 이 객체에 주식을 사면 잔고에서 돈을 빼고, 주식을 팔면 잔고에 돈을 더해 가면서 주식 매매를 해 나갈 것이다. 이 때 내 잔고를 나타내는 변수는 당연히 저장되어야만 이전에 계산된 값에 추가적으로 다른 계산을 해나갈것 아닌가.
인스턴스 변수의 비휘발성은 그렇다 치고, 그러면 클래스라는 것을 왜 쓰고, 왜 인스턴스라는 것을 만들어내는가? 주식매매라는 거대한 프로그램에는 다양한 기능들이 함수들이 있을 것이고, 수많은 변수들이 있을 것이다. 그리고 이것을 사용하는 수많은 이용자들이 있는데, 이 각각의 이용자들이 클래스를 사용하지 않고, 각자 프로그램을 만들어야 한다면 이것은 얼마나 비효율적인가? 그래서 주식매매class를 만들고, 각각의 이용자들에게 붕어빵을 찍어내듯이 인스턴스를 만들어 주는 것이다.
또한 이들이 만약 이 프로그램을 이용하면서 하나의 같은 변수를 사용한다면 어떤일이 벌어지겠는가? 엄청난 혼란이 일어날 것이다. 그래서 인스턴스를 만들면서 각각의 이용자들이 각기 다른 변수명을 갖도록, self.변수명(self==본인의 인스턴스) 을 통해서 다른 변수명을 갖게 되고, 이 변수명은 heap이라는 공간에 저장되어 휘발되지 않고, 이 값에다가 여러가지 계산을 진행할 수 있게 된다.
어떤가? 이제 클래스를 쓰는 이유가 좀 설명이 되는가? 물론, 현실 코딩 세계에서는 클래스와 인스턴스의 개념에 대해서 이론적으로 명확히 알지 못해도 코딩하는데 지장이 없을지도 모른다. 그러나, 이 구조에 대해서 이해 한다는 것은 프로그램의 구조를 이해하는데 도움이 되고, 프로그램의 효율화라는 측면에 대해서 다시 한번 고민하게 되고, 메모리구조와 프로그램간 상호작용 등 많은 부분에 있어서 배움을 얻을 것이라 생각한다.
'프로그래밍 > 기타' 카테고리의 다른 글
docker mysql DB와 django 연동 (0) | 2022.06.26 |
---|---|
C언어 포인터와 call by reference (0) | 2022.02.13 |