본문 바로가기

Programming languages/Python

9. Class

728x90
반응형

오늘은 Class다.

객체지향 프로그래밍의 꽃이라고 볼 수 있다.

필자는 학교 자바 수업 시간에 접해봤는데 대략적인 틀만 알고 정확히 뭔지 감이 잘 오지 않는다.

이번 장을 공부하면서 조금 더 이해가 잘 되면 좋겠다.

 

클래스가 왜 필요한지 이유에 대해서 생각해보자.

클래스는 빵틀과 같다. 파이의 모양을 찍어내는 파이틀이 있다고 해보자.

필자는 피칸파이를 굉장히 좋아한다. 근데 옆에 있는 내 친구는 견과류 알레르기가 있다고 한다.

그럼 파이틀을 이용해서 위에 토핑만 사과로 바꾼다면 애플파이가 될것이다.

어쨌든 '파이틀'을 이용해서 '파이'를 만들었지만 피칸파이, 사과파이 둘은 엄연히 다른 파이다.

심지어 서로 영향을 받거나 끼치지도 않는다. 

비슷한 기능을 여러번 구현할때 중복해서 작동을 기능들이 서로 간섭하지 않게 함수(메소드)들을 묶어놓고

복제해서 갖다 쓰는 느낌이다.

 

apple = Pie(), pikan = Pie() 이러면 apple 과 pikan은 객체이고 Pie의 인스턴스 이다.

인스턴스는 클래스와 객체의 관계를 표현한것이고. 객체는 그 자체로 하나의 객체로 봐주는 것이 좋다.

 

class FourCal: #클래스 생성 클래스명은 대문자 권장
    def setdata(self, first, second): #self는 객체명과 대응 
        self.first = first
        self.second = second



a = FourCal()
a.setdata(16,17) #self는 객체 명과 대응 여기선 a
print(a.first) #호출시 객체명으로 시작
print(a.second)

클래스의 정말 간단한 예시이다. 

a라는 객체를 FourCal()의 인스턴스로 생성한다.

이제 a는 FourCal()이 할 수 있는건 다 할 수 있다.

FourCal()에 구현해 놓은 setdata()를 이용해 보자.

참고로 setdata(self, first, second)에서 self는 객체와 대응된다.

이해하기 쉽게 얘기하면 a.setdata(16,17) == setdata(a,16,17) 이라는 의미다.

물론 위처럼 하면 에러가 발생한다. 이해를 돕기 위한 표현일 뿐이다.

 

class FourCal:
    def setdata(self, first, second):
        self.first = first
        self.second = second



a = FourCal()
a.setdata(16,17)
print(a.first)
print(a.second)
print(id(a.first)) #a.first의 메모리에서의 위치 a와 b가 같음
print(id(a.second)) #a.second의 메모리에서의 위치 a와 b가 다름

b = FourCal()
b.setdata(16,19)
print(b.first)
print(b.second)
print(id(b.first)) #b.first의 메모리에서의 위치 위치 a와 b가 같음
print(id(b.second)) #b.second의 메모리에서의 위치 a와 b가 다름

위의 결과는 다음과 같다.

16
17
4332503760
4332503792
16
19
4332503760
4332503856

 

다른 값을 입력하면 메모리의 서로 다른곳을 가리킨다.

그러나 같은 값을 입력하면 메모리의 같은 곳을 가리킨다.

왜 그런건지 알아 봐야 할것 같다. 분명 객체가 다르면 서로 영향이 없다 했는디,, 어리둥절..?;;;

 

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()
a.setdata(16,4)
print(a.first)
print(a.second)
print(id(a.first)) #a.first의 메모리에서의 위치 a와 b가 같음
print(id(a.second)) #a.second의 메모리에서의 위치 a와 b가 다름
print(a.mul())
print(a.div())

b = FourCal()
b.setdata(27,19)
print(b.first)
print(b.second)
print(id(b.first)) #b.first의 메모리에서의 위치 위치 a와 b가 같음
print(id(b.second)) #b.second의 메모리에서의 위치 a와 b가 다름
print(b.add())
print(b.sub())

위의 결과는 다음과 같다.

 

16
4
4330439376
4330438992
64
4.0
27
19
4330439728
4330439472
46
8

 

결과를 보면 클래스안에 함수를 구현해서 클래스에 인스턴스 된 객체를 통해서 함수를 호출해준 것이다.

 

class FourCal:

    def __init__(self,first,second): #생성자
        self.first = first
        self.second = second

    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(11,17)
print(a.add())

위를 보면 __inti__ 이라는 이름의 특이한 함수가 있을것이다. 이는 생성자 라고 한다.

a라는 FourCal 클래스의 인스턴스를 생성하고 setdata()를 먼저 호출하지 않고 다른 함수를 호출할 경우 에러가 난다.

setdata()를 통해서 값을 입력받아야 연산이 가능할 것이니 오류가 나는 것은 당연하다.

하지만 __init__ 이라는 함수명으로 함수를 만들경우 클래스가 객체로 생성되어 호출 됐을때 가장먼저 실행된다.

즉 인스턴스를 만들고 클래스안의 함수가 호출 됐을때 __init__ 이라는 이름의 함수가 존재 할 경우 가장 먼저 호출이 되는것이다.

쉽게 생각하면 클래스의 초기화 라고 할 수 있겠다.

위의 예제는 __init__ 함수를 setdata와 동일하게 구현해서 setdata의 호출 없이도 인스턴스 객체 생성시 입력 받은 두 값을 바로 이용 할 수 있도록 만든 것이다. 따라서 위의 예제는 28이라는 결과를 출력 하면서 잘 작동한다. 

 

class FourCal:

    def __init__(self,first,second):
        self.first = first
        self.second = second

    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




class MoreFourCal(FourCal):
    def pow(self):
        result = self.first ** self.second
        return result

    def div(self): #div함수 업그레이드
        if self.second == 0:
            return print("0으로 나눌수는 없습니다.")
        else:
            return self.first / self.second


a = MoreFourCal(5,7)

print(a.add())
print(a.mul())
print(a.pow())

b = MoreFourCal(11,0)
print(b.add())
print(b.div())

위의 결과는 다음과 같다.

 

12
35
78125
11
0으로 나눌수는 없습니다.
None

 

하단의 MoreFourCal(FourCal)은 FourCal()을 상속받는 클래스다.

상속이 무엇이냐면 물려받는것이다. 재산상속에서의 상속과 동일한 의미이다.

MoreFourCal()은 FourCal을 상속 받았기 때문에 FourCal()과 동일한 기능을 할 수 있다.

상속의 장점은 부모 클래스(여기서는 FourCal()을 의미한다.)의 수정 없이 새로운 기능을 추가하거나 삭제 가능 하다는 것이다.

심지어 div()의 경우에는 나누는 수가 0일 경우 0은 나눌 수 없다고 출력되게끔 기존 기능을 업그레이드 했다.

이를 Method Overriding 이라고 한다. 부모의 메소드를 호출하지 않고 오버라이딩된 메소드를 호출한다.

이러한 클래스의 상속은 클래스가 라이브러리 형태로 제공되거나 수정이 허용되지 않을경우 상속을 받아서 사용하는 방법으로도 유용하다.

 

class Family:
    name = "Alex"


a = Family()
b = Family()

print(a.name)
print(b.name)
print(Family.name)

print(id(a.name))
print(id(b.name))
print(id(Family.name))

위의 결과는 다음과 같다.

 

Alex
Alex
Alex
4347841648
4347841648
4347841648

 

위를 보면 동일한 내용, 메모리상의 동일한 위치를 가리키는 곳을 알 수 있다.

family class에 선언된 name을 클래스 변수라 한다.

또한 위의 객체에서 호출된 변수가 동일한 메모리 위치를 가리키는 것으로 보아

클래스 변수는 클래스로 만들어진 객체에 공유된다는 것을 알 수 있다.

728x90
반응형

'Programming languages > Python' 카테고리의 다른 글

11.Exception  (0) 2021.12.19
10. Module & Package  (0) 2021.12.19
Examples) Chapter4  (0) 2021.12.12
8. Files  (0) 2021.12.11
7. Input&Print  (0) 2021.12.10