🔦

6편 파이와 썬의 알고리즘 7원석을 찾아서

다루고 있는 개념
자료형
클래스
변수의 타입
난이도
Type
강의
file
 

1. 라이캣의 모험

notion imagenotion image
notion imagenotion image
 
위니브 월드에서는 '알고리즘 7원석'에 대한 이야기로 떠들썩합니다. 알고리즘의 제왕 '파이'와 '썬'이 어딘가에 숨겨둔 알고리즘 7원석을 찾으면 소원을 이뤄준다는 소문이었어요. 수행을 다니던 캣은 생각합니다.
"나는 왕이 되어야겠다냥!"
캣은 멀고 험한 길이 될 것임을 직감했습니다. 그동안 쌓았던 모든 지식이 무용지물이 될 수 있겠다는 생각을 하게 되었고, 새로운 준비를 결심했습니다.
"험한 길이 될거냥. 같으니 단단히 준비해야겠다냥!"
캣은 우선 자신이 지금까지 일구어 놓은 위니브 월드에 회사들을 경영할 대리인을 로봇으로 만들기로 합니다. 지금까지 했던 방식과는 다른 전혀 새로운 방식으로요.
 
 

 
 
  • 라이캣의 상태창!
#[In] 이름 = '캣' 설명 = '위니브 월드에서 가장 성공한 사업가 라이캣, 현재 어디있는지 알 수 없음.' 나이 = 21 오늘_잡은_물고기 = '9999999' 직원수 = 124 키 = '46.1cm' 몸무게 = 1.8 잡식 = True 돈 = 9999999 정치 = 21 야망 = 2 훈장 = [ '백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자' ] 기술 = { '회사운영': 99, '낚시' : 96, '통발' : 93, '큰그물' : 95, '재무' : 34, }
 
 

 

2. 클래스

 
클래스는 데이터와 기능을 가지고 있는 인스턴트 객체를 생성하기 위한 역할을 합니다.
파이썬은 대표적인 객체지향 프로그래밍 언어입니다. 클래스는 일종의 설계도면입니다. 파이썬은 이 설계도면을 보며 하나의 인스턴스 객체를 만들어 냅니다. 그리고 그 인스턴스 객체를 사용할 수 있게 됩니다.
어렵죠? 기억하세요. 지금 캣은 자신을 대리할 대리인을 만드는 것입니다. 따라서, 클래스는 대리인을 찍어내는 공장! 그 공장에서 찍혀져 나오는 인스턴스 로봇이 바로 캣과 똑같은 생각을 하고 똑같이 행동하는 대리인 입니다.
#[In] class 대리인(object): 이름 = '라이캣의 대리인' 훈장 = [ '백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자' ] 기술 = { '회사운영': 99, '낚시' : 96, '통발' : 93, '큰그물' : 95, '재무' : 34, } def 계산하기(self, x): print(int(x)*5000, '원 입니다.') def 포장하기(self): print('포장이 완료되었습니다.') 대리인1 = 대리인() 대리인2 = 대리인() 대리인1.계산하기(5) 대리인1.포장하기() 대리인2.계산하기(10) 대리인2.포장하기() print(대리인1.이름) print(대리인1.훈장) print(대리인2.이름) print(대리인2.훈장)
 
#[Out] 25000 원 입니다. 포장이 완료되었습니다. 50000 원 입니다. 포장이 완료되었습니다. 라이캣의 대리인 ['백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자'] 라이캣의 대리인 ['백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자']
 
그런데 대리인이 이름도 같고 훈장도 같으니, 구분이 안되죠? 그래서 대리인 목록을 하나 만들도록 하겠습니다. 또한 이름이 모두 같으니 이름도 다르게 하겠습니다.
 

2.1 클래스 변수와 인스턴스 변수

 
#[In] class 대리인(object): # 클래스 변수 위치 (파이썬 규약에 따라 indent로 결정) 이름 = '라이캣의 대리인' 대리인_목록 = [] 훈장 = [ '백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자' ] 기술 = { '회사운영': 99, '낚시' : 96, '통발' : 93, '큰그물' : 95, '재무' : 34, } def 계산하기(self, x): print(int(x)*5000, '원 입니다.') def 포장하기(self): print('포장이 완료되었습니다.') 대리인1 = 대리인() 대리인.대리인_목록.append('대리인1') 대리인2 = 대리인() 대리인.대리인_목록.append('대리인2') print(대리인.대리인_목록) print(대리인1.대리인_목록) print(대리인2.대리인_목록)
 
#[Out] ['대리인1', '대리인2'] ['대리인1', '대리인2'] ['대리인1', '대리인2']
클래스 변수는 다른 인스턴스들과 변수를 공유합니다. 이 변수는 메서드(클래스의 함수라고는 부르지 않습니다)의 위치와 동등한 들여쓰기 위치에 자리하고 있습니다.
이 클래스 변수는 위의 예시와 같이 인스턴스나 클래스 이름을 통해서 접근할 수 있습니다. 변수 이름으로 직접 접근을 하지 않는다는 사실을 주의해주세요!
이 클래스 변수는 해당 클래스를 통해 만들어진 모든 인스턴스 객체들이 공유하는 변수 값입니다. 각 인스턴스 객체들 각자가 관리하고 있는 변수는 인스턴스 변수라고 합니다.
위의 예시에서는 인스턴스를 생성할 때마다 어떤 인스턴스가 만들어졌는지 확인하기 위해 인스턴스를 생성할 때마다 대리인.대리인_목록에 접근하여 해당 리스트에 어떤 대리인이 추가되었는지를 표시하고 있습니다.
하지만 이렇게 처음 시작 시에 일일이 메서드를 호출해서 하는 것은 불편하고 실수가 생길 수 밖에 없는 작업입니다. 이런 불편을 해소하기 위해 __init__ 메서드가 있습니다.
언더바가 두개인 이 메서드는 매직 메서드 또는 던더함수라고 합니다. 이것은 다음 장에서 알아보도록 하겠습니다.
이번 장에서는 인스턴스 변수를 통해, 이름을 변경해보죠!
 
#[In] class 대리인(object): 이름 = '라이캣의 대리인' 대리인_목록 = [] 훈장 = [ '백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자' ] 기술 = { '회사운영': 99, '낚시' : 96, '통발' : 93, '큰그물' : 95, '재무' : 34, } def 이름_변경하기(self, name): self.이름 = name def 계산하기(self, x): print(int(x)*5000, '원 입니다.') def 포장하기(self): print('포장이 완료되었습니다.') 대리인1 = 대리인() 대리인.대리인_목록.append('대리인1') 대리인2 = 대리인() 대리인.대리인_목록.append('대리인2') print(대리인1.이름) print(대리인2.이름) 대리인1.이름_변경하기('라이캣하나') 대리인2.이름_변경하기('라이캣둘') print(대리인1.이름) print(대리인2.이름)
 
#[Out] 라이캣의 대리인 라이캣의 대리인 라이캣하나 라이캣둘
 
클래스 변수를 다룰 때는 클래스 자체(예시에서는 대리인 객체)를 이용하여 다루어야 하지만 위의 예시에서 이름을 변경할 때는 각 인스턴스 객체들이 각각 자신의 메서드를 통해 접근을 하고 있습니다. 여기서 self의 정체는 바로, 인스턴스의 영역을 얘기합니다.
앞서 대리인 목록을 모두가 공유했다면, self의 영역은 다른 인스턴스에 해당 변수를 공유하지 않는 고유 영역이라 볼 수 있습니다.
 

2.2 __init__ 함수

자, 이제 __init__을 사용해서, 이름 변경하기를 별도의 메서드가 아닌, 인스턴스가 생성될 때 호출이 되게 해주도록 하겠습니다.
 
#[In] class 대리인(object): 대리인_목록 = [] 훈장 = [ '백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자' ] 기술 = { '회사운영': 99, '낚시' : 96, '통발' : 93, '큰그물' : 95, '재무' : 34, } def __init__(self, name): self.대리인_목록.append(name) self.이름 = name def 계산하기(self, x): print(int(x)*5000, '원 입니다.') def 포장하기(self): print('포장이 완료되었습니다.') 대리인1 = 대리인('라이캣하나') 대리인2 = 대리인('라이캣둘') print(대리인1.이름) print(대리인2.이름) print(대리인1.대리인_목록) print(대리인2.대리인_목록)
 
#[Out] 라이캣하나 라이캣둘 ['라이캣하나', '라이캣둘'] ['라이캣하나', '라이캣둘']
 
이 메서드는 인스턴스 객체 생성 시 자동으로 실행합니다. 어떤가요? 코드가 좀 더 간결해졌습니다!
좀 더 알아보자면 __init__ 메서드는 다른 프로그래밍 언어에서의 생성자(constructor) 역할을 하는 클래스 메서드입니다.
 

2.3 상속

 
#[In] class 대리인(object): 이름 = '라이캣의 대리인' 대리인_목록 = [] 훈장 = [ '백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자' ] 기술 = { '회사운영': 99, '낚시' : 96, '통발' : 93, '큰그물' : 95, '재무' : 34, } def __init__(self, name): self.대리인_목록.append(name) self.이름 = name def 계산하기(self, x): print(int(x)*5000, '원 입니다.') def 포장하기(self): print('포장이 완료되었습니다.') class 진화된_대리인(대리인): #이제 위니브 월드에 있는 대리인들 끼리는 서로 협업합니다. 추가_서로협업하기 = True def 추가된_기능_청소기능(self): print("청소기능이 추가되었습니다.") 대리인1 = 대리인('라이캣하나') 대리인2 = 진화된_대리인('라이캣둘') 대리인2.추가된_기능_청소기능() 대리인2.이름 대리인2.훈장
 
#[Out] 청소기능이 추가되었습니다. None 라이캣둘 ['백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자']
 
클래스를 상속하는 방법은 위의 예시처럼 새로운 클래스의 ()안에 상속할 클래스명을 적어주는 것입니다.
진화된_대리인 클래스는 기존의 대리인 클래스가 사용하던 데이터와 기능들을 모두 사용할 수 있으며, 추가적인 기능을 만들었습니다.
또한 데이터(클래스 변수와 메서드를 재정의할 수 있습니다)를 새로 덮어씌울 수도 있으며 자기 자신만의 클래스 변수를 새로 정의할 수 있습니다.
여기에서 상속을 하는 대리인을 부모 클래스(슈퍼 클래스)라고 부르고 진화된_대리인을 자식 클래스(서브 클래스)라고 부릅니다.

2.4 다중 상속

여러 클래스를 상속받을 때는 아래와 같이 사용하면 됩니다. 다중 상속은 단일 상속 법과 같습니다. 여러개를 상속 받을 때에는 콤마를 사용합니다.
#[In] class 배터리_영구_증가(object): pass class 효율_극대화(object): pass class 대리인(object): 이름 = '라이캣의 대리인' 대리인_목록 = [] 훈장 = [ '백상아리를 잡은 고양이', '성실한 납세자', '해골섬 낚시꾼', '청년 고용 착한 기업', '회사를 설립한 자', '혈통의 인정을 받은 자', '천민을 위한 병원을 세운 자' ] 기술 = { '회사운영': 99, '낚시' : 96, '통발' : 93, '큰그물' : 95, '재무' : 34, } def __init__(self, name): self.대리인_목록.append(name) self.이름 = name def 계산하기(self, x): print(int(x)*5000, '원 입니다.') def 포장하기(self): print('포장이 완료되었습니다.') class 진화된_대리인(대리인, 배터리_영구_증가, 효율_극대화): #이제 위니브 월드에 있는 대리인들 끼리는 서로 협업합니다. 추가_서로협업하기 = True def 추가된_기능_청소기능(self): print("청소기능이 추가되었습니다.")
 

2.5 특별 메소드(magic method)

앞서 말씀드린 것처럼 파이썬에서의 클래스에는 기본적으로 내장하고 있는 특별 메서드들이 있습니다. 파이썬에서는 이런 내장하고 있는 특별 메서드들을 쉽게 재정의하여 사용할 수 있게 되어있습니다. 매직 매서드라고 부릅니다. 혹은 더블 언더바(__)를 쓰고 있는 점에서 줄여서 던더(dunder) 메서드라고도 부릅니다.
 
#[In] class 신규_로봇(object): def __init__(self, name): self.name = name def __getattr__(self, item): print(item + '속성은 존재하지 않습니다.') 로봇1 = 신규_로봇('로봇1') print(로봇1.name) print(로봇1.청소하기)
 
#[Out] 로봇1 청소하기속성은 존재하지 않습니다. None
 
위의 예시에서 __init____getattr__이 특별 메서드입니다. 예시에서 보는 바와 같이 파이썬에 내장되어 있는 특별 메서드들을 쉽게 재정의하여 사용할 수 있습니다.
 
💡
특별 메서드들의 종류를 자세하게 알고 싶다면 파이썬 공식 홈페이지를 참고바랍니다. (https://docs.python.org/3/reference/datamodel.html)
 

2.6 캣의 준비물

자, 그럼 앞서 type 함수를 호출하면 나왔던 class 'int' 는 무엇일까요? 맞습니다. python은 모든 자료형이 class로 되어 있어요! 위니브 월드에 비유해보자면, 사실은 실제하는 캣도, class 였던 것이죠! 이제 대리인의 type과 dir을 찍어보세요. 보다 확연히 알 수 있을 겁니다.
모든 준비가 끝났으니 가볍게 준비물을 챙겨 떠나보도록 하죠. append, insert 등의 매서드를 사용해서 필요한 준비물들을 넣어보세요. 창의력을 발휘해보세요.
여러분들이라면 무엇을 챙겨가시겠나요?
 
# 캣의 준비물 준비물 = [??, ??, ??, ??, ??]
 
자, 이제 제대로 된 여행준비를 하고, 여행을 떠나봅시다.
notion imagenotion image
해당 스토리는 자고일어나니 코딩테스트 시리즈와 이어집니다.
 
Video preview