하루만에 뭔가 다 써버린 느낌이지만.


lecture3.py


# -*- coding:utf-8 -*-
# Python lecture 3
# keeHwan Nam, Dept. of physics, KAIST, 2013.

# class(클래스) 란?
# class는 함수와 자료의 모음이다.
# class는 하나의 자료형이다.

class myClass:
    abc = 0
    b = "AB"
    def myF(self, x, y):
        return x+y

# 위와 같은 식으로 class라는 단어를 사용하여 클래스를 정의한다. 보면 알겠지만, 클래스는 그 안에 변수를 담을 수도 있고, 함수를 담을 수도 있다.


# 클래스를 사용해야 하는 경우는 함수와 자료를 한번에 다룰 때 편한 경우들이다. 예를 들어 보자.

a = myClass() # 정의할 때는 이름인 myClass 뒤에 ()를 붙이지 않았지만, 사용할 때는 붙인다. 왜냐하면, 처음 사용할 때 함수를 불러오기 때문이다.

# 무슨 함수? 잠시 후에 알게 된다. 그렇다 치자.

a.abc = 123

# 위와 같이, 클래스 안에 있는 변수인 abc를 "멤버 변수"라고 한다. 그리고 사용할 때는 a.abc처럼 클래스 변수이름을 먼저 써주고, 점을 찍은 다음 멤버 변수 이름을 써준 다음 사용한다.

a.myF(1, 2)

# 또한, 클래스 안에 있는 함수인 myF를 사용할 수도 있다. 이것을 "멤버 함수"라고 부른다. 사용법은 일반 함수와 같지만, 클래스 변수 이름을 먼저 쓰고 점을 찍어야 한다는 점이 다르다.

# 뭔가 불편해 보이는데 클래스를 왜 사용할까?

# 만약, 어떤 사람이 있는데 이 사람이 이름, 생일, 나이 등의 속성과 걸어다니기, 소리치기 등의 기능이 있다고 해 보자. 그럴 수 있다. 이런 기능을 구현하기 위해서, 리스트를 쓸 수 있다.

def walk(displacement):
    position+=displacement

def shout(sentence):
    play(sentence)

person1 = ["MyName", "05, Jul", 24, walk, shout]

'''
위와 같이 해도 "사람" 처럼 쓸 수는 있다. (이상하게 보이겠지만, 리스트 안에 함수도 들어갈 수 있다. 물론 person1[4](42,24)처럼 사용해도 잘 작동한다!)

하지만, 뭔가 알 수 없는 불편함이 있다. person1[0]이 person1의 이름을 알려준다는 것을 미리 알고 있지 않으면 어떻게 처리할 것인가? 이대로 놔두면, 쓰기만 하는 남들은 몰라도 일단 프로그램을 만들고 있는 내가 불편하다. (물론 파이썬에서는 '키워드'라는 것이 있지만, 일단 넘어가자.)

그래서 이런것들을 해결하기 위해서 클래스라는 개념이 등장한다. 클래스는 위의 모든 것들을 그냥 다 갖고 있는 하나의 덩어리이다.

'''

class person:
    name = ""
    birth = ""
    position = [0, 0]
    def walk(self, displacenemt):
        self.position+=displacement
   

# 간단히 쓰기 위해서 person이 가져야 하는 특성들 몇개만 써 보았다.
# 이제, 어떤 사람을 만들기 위해서는 다음과 같이 사용하면 된다.

person1 = person()
person1.name = "Nam"
person1.birth = "5, Jun"

# 등등등. 대충 위와 같이 쓰면 된다. 여기서 self.라는 녀석이 뭘까? 의문이 들었다면 당신은 파이썬에 소질이 있는 것이다.(라고 본 필자는 생각한다.) 늦지 않은 시점에 self에 대해서 설명할 것이므로 걱정하지 말자.

# 클래스를 왜 써야 하는지 아직 잘 모르겠다면, 일단 클래스라는 것이 있고, 남들이 class 구문을 썼을 때 그게 무슨 뜻이고 어떻게 작동하는지 정도만 이해하고 넘어가도 좋다.


# 위에서는 person1의 속성을 정하기 위해서 person1.name, person1.birth 등등을 나중에 따로 정해주어야 했다. 하지만, 대체로 인간은 날 때부터 생일이 정해지고 이름이 정해진다. 그러므로, 애초에 만들 때 부터 이런 것들을 정해줄 수 있다면 더 좋을 것이다. 그래서 생성자가 존재한다.

class person:
    def __init__(self, givenname, birthday):
        self.name = givenname
        self.birth = birthday

    def walk(self, displacement):
        self.position+=displacement
       
# 위와 같이 클래스를 정의해 보자. 여기서 밑줄 두개__가 붙어있는 함수인 __init__은 매우 중요하다. __init__(self, ...) 이 형식은 그 자체로 쓰이는 정해진 이름이므로 다른 용도로 쓰면 안된다. __init__이 하는 역할은, 클래스 변수가 처음 만들어질 때 입력받은 변수를 이용해서 클래스 멤버들이 가지는 초기값을 정하는 것이다.

# __init__ 은 "생성자(constructor)"라고 부른다.

'''
잠깐. self는 무엇일까? 더이상 이 설명을 늦출 수 없게 되었다.
self는 클래스 변수 자기 자신을 나타낸다. 가령,
person1 = person()
이런식으로 person1이라는 변수가 생겼다고 하자. person1은 클래스 변수이므로, 멤버 변수로 name이 있고, 이 변수를 호출하기 위해서는 person1.name이라고 부르면 된다.
문제는 person1의 안에 있는 함수들이 person1.name을 부르고 싶을 때이다.

왜냐하면, person1의 안쪽에서는 person1이 뭔지 모르기 때문이다. 이런 특징을 변수의 범위(scope)라고 하는데, 잘 모르면 여기서는 넘어가도 좋다. 하지만 scope에 대해서는 언젠가 공부하게 될 것이다. 이런거 잘못 알아서 생긴 오작동은, 손톱밑에 낀 가시처럼 해결하기도 어려우면서 심각하기는 무시무시한 영향을 만들어 낼 수도 있기 때문이다.

person1의 안쪽에 있는 멤버 함수인 walk를 살펴 보자. 그 안에서 position을 부르기 위해서 self.position을 사용했다. person1의 밖에 있는 애들은 position을 사용하기 위해서 person1.position이라고 불러내면 되고, person1의 안에 있는 walk는 position을 사용하기 위해서 self.position을 사용했다.

또 다른 특징은, 멤버 함수를 정의할 때 self가 가장 앞에 들어간다는 점이다. 이것은 파이썬이 가진 중요하면서 이상한 특징인데, 파이썬에서 클래스 안에 있는 멤버 함수들은 자기 자신이 멤버 함수라는 사실을 알기 위해서 변수 중 가장 먼저 self를 인자로 받아야 한다. 뭐 기본이니까 그냥 그러려니 하고 넘어가면 되겠다.

실제로 사용할 때는 person1.walk(displacement)처럼, self는 빼고! 사용해야 한다. 또한, person1의 안쪽에서 불러낼 때에도 self.walk(displacement)처럼 사용하면 된다. 왜 walk(self, displacement)처럼 사용하지 않느냐고 묻는다면, walk(self, displacement)에 있는 self는 self.walk(displacement)처럼 사용할 때 앞으로 빠져나와서 self.가 되었기 때문이다. 이것도 잘 이해가 안간다면 그러려니 하면 된다.

'''

# 생성자를 잘 사용하면 클래스 변수를 편리하게 부려먹을 수 있으므로 어떻게 하면 보다 편하게 될지 잘 생각해 보자.

# 사실은 멤버 함수를 "메소드"라고 부른다. 멤버 함수라고 부르든 메소드라고 부르든 뭐 그렇게 중요하진 않지만.

# 이제 상속(inheritance)에 대해서 알아보자. 프로그래머에게 상속은 알든 모르든 아주 중요한 개념이다.

# 클래스는 자기 자식 클래스에게 자신의 속성을 상속시켜줄 수 있는데, 사용법은 간단하다. 일단 위에서 person이라는 클래스가 정의되어 있었으니 이 클래스를 부모 클래스로 하는 자식 클래스를 하나 만들어 보자.

class korean(person):
    nationality = "KOREA"
    def speak(self):
        print "안녕"

# 위와 같이, person의 속성을 상속 받은 korean이라는 클래스를 만들 수 있다. 사용법은 똑같은데,

jspark = korean("J.S.Park", "9, Oct")

# 위와 같이 그냥 똑같이 사용하면 된다. 아, 그런데 왜 이름과 생일을 처음부터 입력 받을 수 있는걸까? 그것이 바로 '상속'이라는 것이다. korean이라는 클래스는 person의 속성을 그대로 이어받았기 때문에, 생성자__init__()도 그대로 이어받았다.

# 물론 korean의 생성자를 나름대로 새로 정의할 수 있다.

class korean(person):
    nationality = "KOREA"
    def __init__(self, language):
        self.lan = language
    def speak(self):
        print "안녕"

# 나름대로 새로 정의한 생성자를 person에서 정의한 생성자랑 같이 사용하고 싶다면, 다음과 같이 사용해 볼 수도 있다.

class korean(person):
    nationality = "KOREA"
    def __init__(self, language, givenname, birth):
        person.__init__(givenname, birth)
        self.lan = language
    def speak(self):
        print "안녕"

# 대충 이런 식으로 사용할 수 있다. 여러 부모에게서 상속받는 다중상속도 가능한데, 이건 언젠가 설명해 볼 기회가 있을지도 모르겠다.

''' (몰라도 되는 쓸데없는 부연설명) 어떤 사람들은 클래스와 클래스의 상속을 사용할 수 있으니 파이썬이 객체지향형 언어라고 주장한다. 그러나 파이썬은 class가 있기만 할 뿐, 객체지향형 언어에서 클래스가 갖춰야 하는 다형성, 은폐성 등을 기본적으로 지원하지 않는다. 물론 파이썬에서도 사람들끼리의 약속으로 은폐성을 제공하고, 조건문을 복잡하게 사용해서 다형성을 제공할 수 있지만 C++이나 Java에서처럼 간단하게 제공하는 것은 아니다. 물론 이것은 필자 개인의 의견일 뿐으로, 파이썬이 객체지향헝 언어의 특성을 갖고 있다는 점을 부정하고 싶지는 않다. 또한, 객체지향형 언어로 할 수 있는 것을 모두 할 수 있다는 점을 부정할 수 없다. 단지, 객체지향형 언어의 모든 특성을 갖고 있는 완전한 객체지향형 언어가 아니라고 말하고 싶을 뿐이다.
'''

by snowall 2013. 7. 25. 01:39