2022/01/01/SAT
- 참고 : github.com/guebin 최규빈 교수님 강의 자료
- 많은 교재에서 정의를 회피함
- 비유적 설명 , 다른 대상을 가져와서 설명
- 클래스는 과자틀과 비슷하다. 클래스란 똑같은 무엇인가를 계속 만들어 낼 수도 있는 설계도면이고 객체란 클래스로 만든 피조물을 뜻한다.
- 직접적 설명
- 복제를 위한 확장가능한 프로그램 코드의 유닛
밈의 예제로 돌아가보자.
(1) 무야호 원본 시청
(2) 복사하고 싶은 속성을 추림
(3) 복제가능한 어떤 밈(틀)을 만듬
- 틀1: 무야호~~~ -> 그만큼 ~하셨다는거지?
- 틀2: 무야호 + 영상샘플링 + 음악샘플링
(4) 밈으로부터 짤을 만든다.
좀더 정리하여 말하면,
(1) 개념의 인지
(2) 복사하고 싶은 속성을 추림
(3) 복사가능한 어떤 틀을 만듬 (=클래스를 정의)
(4) 틀에서 인스턴스를 만든다 (=클래스에서 인스턴스를 만든다)
농심에서 나온 무파마를 먹고, 너무 맛있어서 갑자기 밈으로 놀고 싶어졌다.
from PIL import Image
Image.open('mooyaho1.jpg').resize((200,200))
title="농심 무파마"
img=Image.open('mooyaho1.jpg').resize((200,200))
don="그만큼 맛있으시단거지"
print(title)
display(img)
print(don)
- 짤을 변경하고 싶다면, 아래와 같이 수행하자.
title="속 시원한 농심 무야호"
print(title)
display(img)
print(don)
첫 시도의 허점
- 변용 가능한 여러개 짤을 관리하기 힘들다.
- 불필요한 반복도 많다. print, display, print <-- 짤을 만들때마다 반복
- 코드가 지저분하다. (디버깅이 힘들다)
import mooyaho
mooyaho.memeshow(mooyaho.title, mooyaho.img,mooyaho.don)
- 타이틀을 바꾸고싶다면?
mooyaho.title='속시원한 농심 무야호'
mooyaho.memeshow(mooyaho.title, mooyaho.img, mooyaho.don)
- 두 번째 시도의 아쉬운 점
- 코드는 상대적으로 깔끔하지만, 함수부분이 조금 아쉽다.
- 코드를 수정할때마 커널재시작을 해야한다.
class MooYaHo(): ### MooYaHo라는 이름을 가진 클래스 선언
title="농심 무파마" ### 클래스안에서 정의된 변수1
img=Image.open('mooyaho1.jpg').resize((200,200)) ### 클래스안에서 정의된 변수2
don="그만큼 맛있으시단거지" ### 클래스안에서 정의된 변수3
def memeshow(self): ### 클래스안에서 정의된 함수*
print(self.title)
display(self.img)
print(self.don)
- 모듈버전과 비교해보자.
from PIL import Image
title="농심 무파마" ### 모듈안에서 정의된 변수1
img=Image.open('mooyaho1.jpg').resize((200,200)) ### 모듈안에서 정의된 변수2
don="그만큼 맛있으시단거지" ### 모듈안에서 정의된 변수3
def memeshow(title,img,don): ### 모듈안에서 정의된 함수
print(title)
display(img)
print(don)
$\to$ 모듈버전이랑 비교하니까 함수부분이 조금 다르다.
$\to$ 혹시 모듈처럼 아래와 같이 클래스를 선언해도 되지 않나?
class MooYaHo(): ### MooYaHo라는 이름을 가진 클래스 선언
title="농심 무파마" ### 클래스안에서 정의된 변수1
img=Image.open('mooyaho1.jpg').resize((200,200)) ### 클래스안에서 정의된 변수2
don="그만큼 맛있으시단거지" ### 클래스안에서 정의된 변수3
def memeshow(title,img,don): ### 클래스안에서 정의된 함수
print(title)
display(img)
print(don)
$\to$ 안 됨 (자세한 이유는 나중에)
규칙1: 클래스내에서 함수를 선언하면 반드시 첫번째 인자는 self를 넣어야 한다. --> self가 뭘까?
규칙2: 클래스 내에서 정의한 변수 (예를들면 title, img, don)를 사용하려면
self.title,self.img,self.donMooYaHo.title,MooYaHo.img,MooYaHo.don
Step1: 클래스에서 인스턴스를 만듬
Step2: 인스턴스에서 memeshow라는 함수를 사용
클래스에서 인스턴스를 찍어내는 방법
- 함수사용법과 비슷
- 클래스 이름을 쓰고 콘텐츠를 구체화시키는 과정에서 필요한 입력1, 입력2를 ()에 넣는다.
- MooYaHo의 경우는 따로 입력이 없으므로, 그냥 MooYaHo하고 입력을 비워둔다. 즉
MooYaHo()로 생성
moo1=MooYaHo() ### 첫번째 인스턴스 생성
moo1?
Type이 MooYaHo $\dots$
원래 Type은 int, float, list 이어야 할텐데..? int 가 클래스이름이었나? $\to$ 일단 나중에
밈의 속성 확인
moo1.하고 탭을 눌러봤더니 아래 같은 것들이 나왔다
- 주황색:
don,img,title - 파란식:
memeshow<- 함수- 함수의 입력: self
- 함수의 기능: print, display, print
moo1.memeshow()
성능1: 인스턴스에서 .을 찍고 접근할 수 있는 여러 자료들을 정의할 수 있다.
moo1.title
성능2: 인스턴스에서 .을 찍고 쓸 수 있는 자체적인 함수(=method라고 함)를 정의할 수 있다.
moo1.memeshow()
성능3: 짤의 내용을 쉽게 바꿀 수 있다.
moo1.title="속까지 시원해지는 농심 무야호"
moo1.memeshow()
moo1.don="그만큼 시원하시다는 거지"
moo1.memeshow()
성능4: 여러짤을 동시에 쉽게 컨트롤 할 수 있다.
moo2=MooYaHo()
moo3=MooYaHo()
moo2.title="오뚜기 진야호"
moo2.don="그만큼 진하시다는 거지~"
moo2.memeshow()
moo3.title="팔도 비야호"
moo3.don="그만큼 비비고 싶으셨단 거지~"
moo3.memeshow()
moo2.memeshow()
성능 5: 틀의 재설계(밈의 재설계) $\star$$\star$$\star$
출력만 살짝 바꾸어서 MooYaHo2를 만들고 싶다. --> MooYaHo의 모든 내용은 그대로 가져오고, 그 살짝만 다시 조정하면 된다.
#### 이런식으로 할 필요 없다.
class MooYaHo2(): ### MooYaHo라는 이름을 가진 클래스 선언
title="농심 무파마" ### 클래스안에서 정의된 변수1
img=Image.open('mooyaho1.jpg').resize((200,200)) ### 클래스안에서 정의된 변수2
don="그만큼 맛있으시단거지" ### 클래스안에서 정의된 변수3
def memeshow(self): ### 클래스안에서 정의된 함수*
print('☆☆☆☆☆☆['+self.title+']☆☆☆☆☆☆')
display(self.img)
print('형돈:'+self.don)
class MooYaHo2(MooYaHo):
choi='무야~~~~~호~~~!!!'
def memeshow(self): ### 클래스안에서 정의된 함수*
print('☆☆☆☆☆☆['+self.title+']☆☆☆☆☆☆')
display(self.img)
print(self.choi)
print('형돈:'+self.don)
moo4=MooYaHo2()
moo4.memeshow()
moo5=MooYaHo2()
moo5.title='오뚜기 진야호'
moo5.don='그만큼 진하시다는 거지'
moo5.memeshow()
clss안에 있는 함수는 첫번째 인자로 self를 받고 변수 사용할 때는 self.이라고 사용
아래 셀에서 Meme은 class의 name이다
import numpy
class Meme: # class Meme():
n=0 #짤 생성 횟수
title="농심"
def memeshow(self):
self.n+=1
print(self.title)
print("*****")
print(numpy.random.normal())
print("*****")
print(str(self.n)+'번째 짤')
ins1=Meme()
ins1.memeshow()
ins2=Meme()
ins2.title='삼양'
ins2.memeshow()
ins2.n
ins1.n
ㄴㅇㄱ 아?! self에 들어가야했던것은 사실 인스턴스 이름이었음.
그런데 인스턴스 이름은 모른다. (내가 뭘로 만들지 알고? )
그래서 그냥 self로 하는것임.
아래코드가 아쉽다.
$\to$ 왜 아쉽지?
$\to$ 왜 굳이 default가 농심이여서 instanc 생설할 때마다 title을 수정해줘야지?
ins2=Meme()
ins2.title='삼양'
title이 無디폴트였으면 좋겠다.
__init__
인스턴스가 생성되는 시점에 자동 실행- 특별한 첫번째 인자를 가진다(self)
- 클래스를 인스턴스화 할때 ( )의 값들을 함수의 입력으로 받는다.
Meme2 라는 새로운 class를 정의中
class Meme2:
n=0
def __init__(a,title):
a.title=title
def memeshow(a):
a.n=a.n+1
print(a.title)
print("*****")
print(numpy.random.normal())
print("*****")
print(str(a.n)+'번째 짤')
ins3=Meme2('팔도')
ins3.title
ins3.memeshow()
(1) Meme2()를 인스턴스화 하는 순간에 __init__ 이 실행되어야함.
(2) 그런데 __init__의 첫번째 인자인 self는 입력 안해도 된다고 치고, 두번째 인수인 title은 입력으로 받았어야만 하는것인데, 입력으로 받지못하여 에러메시지 발생.
(3) 도대체 그럼 언제 __init__의 두번째 인수인 title을 넣어야할까? 곰곰히 생각해보니 Meme2를 인스턴스화 하는 순간에 입력으로 넣었어야 논리적으로 맞다. 즉 ins3=Meme2('팔도')와 같은 식으로 생성하는 순간 입력으로 넣어야 하는 것이었음.
(4) __init__의 두번째 인자가 '팔도'로 입력되었고, 이것이 self.title 즉 ins3.title에 바로 업데이트 된 상황임.
코드의 효율적인 수정
Meme2는 Meme을 상속받는 中
class Meme2(Meme):
def __init__(self,title):
self.title=title
ins3=Meme2('팔도')
ins3.memeshow()
ins4=Meme2('오뚜기')
ins4.memeshow()
욕심: 타이틀이 없다고 에러메시지를 띄우는것 보다 없으면 없는대로 만들어도 되지 않을까?
class Meme3(Meme):
def __init__(self,title=None):
self.title=title
ins5=Meme3()
ins5.title
title을 None으로 설정해놔서 title이 출력되지 않은 상황임
ins5.memeshow()
ins5.title='야구르트'
ins5.title
ins5.memeshow()