본문 바로가기
Python

18. 파이썬 클래스2(class)

by To올라운더 2023. 7. 11.
반응형

지난 시간 알아본 구조 및 매서드, 생성자를 지나, 초급과정 마지막 수업인 클래스(class)의 클래스변수와 멤버변수, 상속, 오버라이딩에 대해 정리해보겠다.

지난 과정을 복습하려하는 분은 아래글을 참고하시기 바랍니다.

2023.07.10 - [IT 배우기/Python] - 17. 파이썬 클래스1(class)

 

17. 파이썬 클래스1(class)

드디어 길었던 1차 교육과정의 마지막인 클래스(class)를 배워볼 시간이 되었다. 우리는 앞선 과정에서 반복되거나 여러개의 기능을 관리(또는 처리)해야 할 때 리스트나 딕셔너리 같은 별도의 자

to-all-rounder.tistory.com

 

5. 클래스변수와 멤버변수

  - 이전 포스팅(클래스1)에서 잠시 언급한 클래스 변수와 멤버 변수를 먼저 다뤄보면,

  - Clothes 클래스 내에 self가 없이 선언된 made_country라는 변수와 생성자(__init__)안에 self와 함께 선언된 size라는 변수가 있다.

 

  1) 클래스변수

  - 클래스 안에서 self가 없이 선언된 변수를 클래스 변수라고 하는데,

   30라인처럼 '클래스명.클래스변수명'을 통해서 해당 값을 수정 할 수 있고,

  - 32, 34라인 처럼 Clothes의 동일한 클래스로 생성된 두 a, b 인스턴스의 변수 값이 같이 태국으로 변경된 것을 볼 수 있다.

  - 다른 의미로 클래스 변수는 모든 인스턴스 객체들이 공통으로 사용하는 값이라는 의미이며, 해당 변수가 문자형이 아닌 튜플, 리스트, 딕셔너리 등 우리가 알고 있는 모든 자료형들이 클래스 변수로 사용될 수 있다. 

  - 31, 33 라인에 표시된 size 멤버 변수의 경우, 클래스 변수가 변경되더라도 무관하게 원래의 값을 유지함을 볼 수 있다.

 

  2) 멤버변수

  - 클래스 안에서 self를 포함하여 선언된 각 개체의 변수를 멤버변수라고 하는데,

    멤버 변수의 값은 각 개체의 고유한 값으로 다른 객체의 값이 변경되더라도 영향을 받지 않는다.

  - 실제 a 인스턴스에는 made_country 라는 클래스변수만 있고, 멤버변수는 없었으나,

    38라인에서 a.made_country 의 형태로 멤버변수를 선언해주면 그 결과는 40, 42 라인 처럼 a 인스턴스는 변경된 멤버변수 값(중국), b 인스턴스는 기본 클래스변수 값(태국)이 출력됨을 알 수 있다.

    (*추가로 a.made_country를 확인할 때 보았듯이 같은 변수명을 가질 경우, 클래스변수보다는 멤버변수가 우선시된다.)

class Clothes: # 암묵적인 약속으로 클래스명의 첫글자는 대문자를 사용한다.
    
    made_country = '필리핀'

    def __init__(self, meterial, size, color, model_no):
        self.meterial = meterial
        self.size = size
        self.color = color
        self.model_no = model_no

    def beautiful(self):
        result = f'옷이 날개. model_no{self.model_no}만 입어도 연예인'
        #print(result)
        return result
        

print('-'*30, '기본 값', '-'*30)
a = Clothes('솜', '100', '검정', '22') # a 인스턴스 생성
print('a 메서드 실행')
print(f'a 인스턴스 생성 시 할당된 size 멤버변수 : {a.size}')
print(f'a 인스턴스 생성 시 할당된 made_country 클래스변수 : {a.made_country}')

b = Clothes('나일론','105','아이보리','30') # b 인스턴스 생성
print('b 메서드 실행')
print(f'b 인스턴스 생성 시 할당된 size 멤버변수 : {b.size}')
print(f'b 인스턴스 생성 시 할당된 made_country 클래스변수 : {b.made_country}')
print('-'*30, '기본 값', '-'*30,'\n\n')

print('-'*30, '클래스변수 수정(->태국)', '-'*30)
Clothes.made_country = '태국'
print(f'클래스변수 수정 후 a 인스턴스 size 멤버변수 : {a.size}')
print(f'클래스변수 수정 후 a 인스턴스 made_country 클래스변수 : {a.made_country}')
print(f'클래스변수 수정 후 b 인스턴스 size 멤버변수 : {b.size}')
print(f'클래스변수 수정 후 b 인스턴스 made_country 클래스변수 : {b.made_country}')
print('클래스변수 수정 시, 모든 인스턴스에 동일하게 적용됨 확인\n\n')

print('-'*30, '멤버변수 수정(->중국)', '-'*30)
a.made_country = '중국'
print(f'a 인스턴스의 멤버 변수를 직접 수정 후 a.size 멤버변수 확인 : {a.size}')
print(f'a 인스턴스의 멤버 변수를 직접 수정 후 a.country 멤버변수 확인 : {a.made_country}')
print(f'a 인스턴스의 멤버 변수를 직접 수정 후 b.size 멤버변수 확인 : {b.size}')
print(f'a 인스턴스의 멤버 변수를 직접 수정 후 b.country 멤버변수 확인 : {b.made_country}')
print('멤버변수 수정 시, 해당 인스턴스에만 수정사항 적용됨 확인\n\n')

 

 

2. 상속

 - 부모의 재산을 자녀가 상속 받듯이 클래스 내에서도 상위(부모) 클래스의 속성이나 메소드들을 상속받을 수 있다.

 - 상위 클래스(Super class)를 동일한 의미로 부모클래스(Pararent class), 기초클래스(Base class) 라고도 부르며,

   반대로 하위클래스(Sub class)를 자식클래스(Child class), 파생클래스(Derived class)라고 대칭해서도 부른다.

 - 상속을 사용하는 이유는 이미 있는 속성과 매서드를 재정의할 필요 없이 재사용하는 것이 훨씬 효율적이기 때문이다.

 - 또 상위클래스가 라이브러리 형태로 제공되거나 수정 시 다른 클래스나 인스턴스들에 장애가 발생하는 요소를 회피하기 위해 상속을 사용한다.

 - 방법은 간단하다. 상위클래스를 선언한 후, 자식 클래스에 상속할 부모클래스명을 괄호 안에 입력하면된다.

 - 19라인에서 사용된 super() 는 상위클래스의 멤버변수를 상속 받는 것을 뜻한다.

class Clothes: # 암묵적인 약속으로 클래스명의 첫글자는 대문자를 사용한다.
    
    made_country = '필리핀'

    def __init__(self, meterial, size, color, model_no):
        self.meterial = meterial
        self.size = size
        self.color = color
        self.model_no = model_no

    def beautiful(self):
        result = f'옷이 날개. model_no{self.model_no}만 입어도 연예인'
        #print(result)
        return result


class Dress(Clothes):
    def __init__(self, meterial, size, color, model_no):
        super().__init__(meterial, size, color, model_no)
    
    def juwel(self):
        
        self.personal_juwel = '루비'
      

d = Dress('실크','100','white','D-1')
print(d.size)
print(d.beautiful())
d.juwel()
print(d.personal_juwel)

 - 유의할 사항은 d.personal_juwel 을 출력하기 위해서 29라인에서 juwel 매서드를 실행시켜줘야 한다는 사실이다.

   (29라인 없이 실행할 경우, 에러가 발생하는데, 인스턴스가 생성될 때에는 생성자(__init__)만 1회 실행되고, 다른 매소드들은 실행 되지 않기 때문에, d 인스턴스의 personal 멤버변수는 정의(선언)되지 않은 상태이다.)

 

3. 오버라이딩

  - 만약 하위 클래스에 상위 클래스의 매소드와 같은 이름의 매소드가 생성된다면 어떻게 될까?

  - 아래의 예시와 같이 동일한 매소드 명(beatiful)으로 하위 클래스에서 생성이되면,

    하위 클래스의 매소드가 실행됨을 알 수 있다.

  - 이런 하위 클래스에 매소드명이 상위 클래스의 매소드명과 같고 다른 동작(상위 클래스의 매소드를 무시하는 동작)을 하는 것을 오버라이딩이라 한다. 

class Clothes: # 암묵적인 약속으로 클래스명의 첫글자는 대문자를 사용한다.
    
    made_country = '필리핀'

    def __init__(self, meterial, size, color, model_no):
        self.meterial = meterial
        self.size = size
        self.color = color
        self.model_no = model_no

    def beautiful(self):
        result = f'옷이 날개. model_no{self.model_no}만 입어도 연예인'
        #print(result)
        return result


class Dress(Clothes):
    def __init__(self, meterial, size, color, model_no):
        super().__init__(meterial, size, color, model_no)
    
    def juwel(self, personal_juwel):
        
        self.personal_juwel = personal_juwel
        
    
    def beautiful(self):
        result = f'{self.personal_juwel}와 어울리는 최고의 드레스'
        return result

      

d = Dress('실크','100','white','D-1')
print(d.size)
d.juwel('루비')
print(d.personal_juwel)
print(d.beautiful())

  - 오버라이딩을 쓰는 이유는 간단한다. 계속 언급되는 효율성인데, 상위 클래스에서 선언된 매소드가 코드 내에 여러 곳에 작성이 되어 있을 때, 같은 매소드명이 아닌 다른 매소드명으로 매소드를 만들게되면 원하는 부분에 모두 매소드명 수정이 진행되어야 한다. 그러나 동일한 매소드명으로 하위클래스에 매소드를 만들게되면 상위 클래스를 무시하고 해당 인스턴스에서 내가 원하는 매소드 동작을 할 수 있다.

 

4. 오버라이딩 적용 후, 부모 클래스의 동일한 매소드명 사용하기

  - 여러 곳에 수정을 피하기 위해 동일한 매소드명을 하위클래스에서 사용(오버라이딩)하는데, 이런 상황과는 반대로 기존의 상위클래스의 매소드를 그대로 사용하고 싶을 때가 있다....(필요 없다고 무시하더니, 또 쓰고 싶을 때는 생기는 아이러니이다. 사람의 마음이 그때 그때 오락가락 한다...)

  - 31라인을 보면 super() 를 이용하여 상위클래스를 불러오고, 상위클래스의 매소드명을 호출할 수 있음을 알 수 있다.

  - 자세히 생각해보면 최초 상속을 받는 18,19 라인도 'super().__init__' 의 형태는 상위클래스의 생성자를 그대로 실행하기 위한 형태라는 것을 알 수 있다.

   (* 만약, 오버라이딩(26~28) 라인이 선언되지 않았다면, 일을 두번으로 나눌 필요없이 상속 받은 매소드를 바로 사용할 수 있다.)

class Clothes: # 암묵적인 약속으로 클래스명의 첫글자는 대문자를 사용한다.
    
    made_country = '필리핀'

    def __init__(self, meterial, size, color, model_no):
        self.meterial = meterial
        self.size = size
        self.color = color
        self.model_no = model_no

    def beautiful(self):
        result = f'옷이 날개. model_no{self.model_no}만 입어도 연예인'
        #print(result)
        return result


class Dress(Clothes):
    def __init__(self, meterial, size, color, model_no):
        super().__init__(meterial, size, color, model_no)
    
    def juwel(self, personal_juwel):
        
        self.personal_juwel = personal_juwel
        
    
    def beautiful(self):
        result = f'{self.personal_juwel}와 어울리는 최고의 드레스'
        return result

    def super_beautiful(self):
        return super().beautiful()

      

d = Dress('실크','100','white','D-1')
print(d.size)
d.juwel('루비')
print(d.personal_juwel)
print(d.beautiful()) # 오버라이딩
print(d.super_beautiful()) # super를 이용한 상위클래스의 동일한 매소드명 실행

 

이제 정말 초급 과정은 끝이 났다.

무언가 배웠지만, 내가 뭘 배웠는지 무엇을 할 수 있는지 모를 것이다.

 

정상이다. 이제 진짜 무언가를 만들어볼 예정이다.

내가 지금까지 배운것 만으로 무언가를 만들 수 있을까라는 고민은 필요없다.

모듈이라는 다른 사람들이 미리 만들어 놓은 것들을 활용하면 훨씬 대단한 것들을 만들 수 있다.

 

이제 사전에 계획했던 2차 과정을 진행할 예정이다.

2차 과정은 API와 파일을 다뤄보고 실제로 무언가를 만들 예정이다.

(아직은 비밀....다음 포스팅에서...)

 

무언가 허전하다면, 일단 초급과정에 대해 익숙해지자. 반복과 복습은 학습에 가장 큰 도움이된다.

그동안 짧지 않은 시간이었지만, 초급 1차 과정 동안 수고하셨습니다.

반응형

'Python' 카테고리의 다른 글

20. 파이썬 네이버 API(Papago) 연동하기1  (0) 2023.07.18
19. 파이썬 API 연동하기  (0) 2023.07.12
17. 파이썬 클래스1(class)  (1) 2023.07.10
16. 예외 처리(try, exception)  (0) 2023.07.05
15. 파이썬 함수  (0) 2023.07.04