• 참고 : github.com/guebin 최규빈 교수님 강의 자료

- 밈? 인터넷 밈?

  • 한 사람 혹은 집단에서 다른 지성으로 생각 혹은 믿음이 전달될 때 전달되는 모방 가능한 사회적 단위를 총칭

인터넷 밈

  • 밈의 한 형태
  • 인터넷을 통해 사람들에게 전파되는 어떤 생각, 행동, 스타일 등

클래스

  • 많은 교재에서 정의를 회피함
  • 비유적 설명 , 다른 대상을 가져와서 설명
    • 클래스는 과자틀과 비슷하다. 클래스란 똑같은 무엇인가를 계속 만들어 낼 수도 있는 설계도면이고 객체란 클래스로 만든 피조물을 뜻한다.
  • 직접적 설명
    • 복제를 위한 확장가능한 프로그램 코드의 유닛

밈의 예제로 돌아가보자.

(1) 무야호 원본 시청

(2) 복사하고 싶은 속성을 추림

(3) 복제가능한 어떤 밈(틀)을 만듬

  • 틀1: 무야호~~~ -> 그만큼 ~하셨다는거지?
  • 틀2: 무야호 + 영상샘플링 + 음악샘플링

(4) 밈으로부터 짤을 만든다.


좀더 정리하여 말하면,

(1) 개념의 인지

(2) 복사하고 싶은 속성을 추림

(3) 복사가능한 어떤 틀을 만듬 (=클래스를 정의)

(4) 틀에서 인스턴스를 만든다 (=클래스에서 인스턴스를 만든다)


[예제1]

농심에서 나온 무파마를 먹고, 너무 맛있어서 갑자기 밈으로 놀고 싶어졌다.

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.don
  • MooYaHo.title, MooYaHo.img, MooYaHo.don

밈으로 부터 짤을 만든다. (클래스로부터 인스턴스를 생성한다.)

Step1: 클래스에서 인스턴스를 만듬

Step2: 인스턴스에서 memeshow라는 함수를 사용

클래스에서 인스턴스를 찍어내는 방법

  • 함수사용법과 비슷
  • 클래스 이름을 쓰고 콘텐츠를 구체화시키는 과정에서 필요한 입력1, 입력2를 ()에 넣는다.
  • MooYaHo의 경우는 따로 입력이 없으므로, 그냥 MooYaHo하고 입력을 비워둔다. 즉 MooYaHo()로 생성
moo1=MooYaHo() ### 첫번째 인스턴스 생성
moo1?
Type:        MooYaHo
String form: <__main__.MooYaHo object at 0x0000024E7565C730>
Docstring:   <no docstring>

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()
☆☆☆☆☆☆[오뚜기 진야호]☆☆☆☆☆☆
무야~~~~~호~~~!!!
형돈:그만큼 진하시다는 거지

예제2

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()
농심
*****
0.2916597433173283
*****
2번째 짤
ins2=Meme()
ins2.title='삼양'
ins2.memeshow()
삼양
*****
0.608642243170386
*****
1번째 짤
ins2.n
1
ins1.n
2

ㄴㅇㄱ 아?! self에 들어가야했던것은 사실 인스턴스 이름이었음.

그런데 인스턴스 이름은 모른다. (내가 뭘로 만들지 알고? )

그래서 그냥 self로 하는것임.

#### 예제3

아래코드가 아쉽다.

$\to$ 왜 아쉽지?

$\to$ 왜 굳이 default가 농심이여서 instanc 생설할 때마다 title을 수정해줘야지?

ins2=Meme()
ins2.title='삼양'

title이 디폴트였으면 좋겠다.

인스턴스를 만들때마다 타이틀을 새로 정하는 방식이 있으면 좋겠다.

그 대안이 : __init__

__init__

  • 인스턴스가 생성되는 시점에 자동 실행
  • 특별한 첫번째 인자를 가진다(self)
  • 클래스를 인스턴스화 할때 ( )의 값들을 함수의 입력으로 받는다.

Meme2 라는 새로운 class를 정의中

*주의*

def `__init__`(self,title):

에서 self.title이 아니라 self,title같이 콤마를 사용해야한다.

그런데 첫번째 인자를 굳이 self로 안 받아도 되는 것 같긴 함

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.9895310742180208
*****
3번째 짤

(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()
팔도
*****
-2.1018660318391236
*****
1번째 짤
ins4=Meme2('오뚜기')
ins4.memeshow()
오뚜기
*****
0.25483170477981176
*****
1번째 짤

욕심: 타이틀이 없다고 에러메시지를 띄우는것 보다 없으면 없는대로 만들어도 되지 않을까?

class Meme3(Meme):
    def __init__(self,title=None):
        self.title=title
ins5=Meme3()
ins5.title

title을 None으로 설정해놔서 title이 출력되지 않은 상황임

ins5.memeshow()
None
*****
0.6307634191745345
*****
1번째 짤
ins5.title='야구르트'
ins5.title
'야구르트'
ins5.memeshow()
야구르트
*****
-1.3387268900814815
*****
2번째 짤