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


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.07.25 01:39
  • 페이지 2013.12.12 04:11 신고 ADDR EDIT/DEL REPLY

    안녕하세요, 파이썬 클래스 공부하다가 여기까지 흘러온 비전공자인데요 ㅜ ㅜ, 저는 코드아카데미로 공부를 하고 있어서 개념 정의가 살짝 헷갈리는 부분 여쭤봅니다. 제가 보았던 부분은
    It may surprise you to learn that not all variables are accessible to all parts of a Python program at all times. When dealing with classes, you can have variables that are available everywhere (global variables), variables that are only available to members of a certain class (member variables), and variables that are only available to particular instances of a class (instance variables).

    여기서 global 변수는 어디에서나 통용되는 일반 변수라면, member 변수는 클래스 내에서 self.xxx, 즉 attribute(속성) 이라고 봐도 되나요? 그리고 instance가 찾아보니까 클래스가 있으면 그 클래스를 통과해서 만든 객체라고 하더라구요~! 위 예제처럼 jspark = ~~ 일 때, jspark를 instance 변수라고 하면 제가 제대로 이해한 게 맞는지 여쭤봅니당 ㅠㅠ

    • snowall 2013.12.12 10:38 신고 EDIT/DEL

      저는 별로 구분 안하고 쓰다보니...
      클래스에서 명시적 선언을 하고 만든 변수가 멤버 변수이고, 클래스 안에서 임시로 만든 변수가 인스턴스 변수네요.
      http://www.python.org/doc/essays/ppt/acm-ws/sld051.htm
      위의 예제를 보면 알 수 있는데요
      클래스 안에서 만든 변수 verbose는 첫줄에서 선언이 되어 있으니까 멤버 변수이고, host는 __init__메소드에서 만든 변수라서 인스턴스 변수입니다.
      멤버변수는 클래스의 인스턴스가 만들어지면 항상 만들어 지는데, 인스턴스 변수는 클래스에서 그 인스턴스를 만들어 내는 메소드가 실행되지 않으면 없을수도 있어요.
      위의 예제를 보면
      con = Connection(hostname)
      이렇게 해서 Connection 클래스를 사용한다면
      con.verbose는 항상 존재하는 변수가 되고(멤버변수)
      con.host는 __init__이 실행되어야만 존재하고, 만약 실행되지 않는다면 존재하지 않습니다. (인스턴스변수) 여기선 하필 항상 실행되는 __init__에다 넣어놔서 헷갈리시겠지만.

      그래서, con.verbose를 쓰려고 하면 항상 가능합니다. 그러나 con.host를 쓰려고 하면 에러가 나는 경우도 있을 수 있다는 거죠.
      (__init__이 항상 실행되므로 실제로 위와 같이 쓰면 에러가 안 나겠지만. 귀도가 왜 저딴식으로 설명해놨는지 모르겠군요.)

    • snowall 2013.12.12 10:48 신고 EDIT/DEL

      http://www.python.org/doc/essays/ppt/acm-ws/sld052.htm
      그래서 그 다음장 슬라이드를 보면 뭘 써놨는데요
      클래스 변수는 같은 클래스의 인스턴스들이면 다 같은 값을 갖고
      인스턴스 변수는 인스턴스마다 다 다를 수 있다고 되어 있네요

      다시말해서, 방금 그 예제에서 con.verbose는 처음에는 0이고, 이 값은 connection 클래스의 인스턴스를 새로 만들때마다 0이라고 정해져 있을 거예요. 그런데 con.debug에서 v를 바꾸게 되면 이 순간부터 verbose는 클래스 변수에서 인스턴스 변수가 됩니다. 왜냐하면 클래스의 인스턴스마다 다 같은 값이 아니라, 이 인스턴스에서 바꿨으니까 얘만 다른 값을 갖는다는 거죠.

      정말 쓸데없이 복잡하게 써놨는데요. 파이썬에는 변수의 변경을 금지하는 상수 지정자가 없어서 굳이 구분해둔 것 같네요.

      쉽게 말해서,
      1.클래스 자체에서 선언하고
      2.안 변하면
      ==클래스 변수

      1.클래스 안의 멤버 변수인데
      2.변하면
      ==인스턴스 변수

      이런겁니다.

      윗 댓글에서 host는 없다가 생긴 변수이므로, 이것도 변했다고 보고 인스턴스 변수가 됩니다.

      이건 차라리 개념이 없는게 나을듯 싶군요...
      어차피 모든 변수를 다 고치는 것이 가능한 상황에서, 얘를 건드렸는지 안 건드렸는지 프로그래머가 신경써야 한다는 뜻이니까요. 말로 이름만 붙여놓은거지 사실 아무 차이 없습니다.

  • paige 2013.12.13 00:02 신고 ADDR EDIT/DEL REPLY

    헐 제가 차단당해서 이렇게 댓글달아요ㅠㅠㅠ 당황해서 생각해봤는데 제가 그냥 댓글만 확인하고 가버린게 아니었어요 그게아니라 너무 어려워서 다시 머리속으로 정리해보고 댓글달려 한건데...ㅠㅠㅠ 오해하신 것 같아요 아무튼 아래는 원래 달려던 댓글이에요 ㅠㅠ

    정말로 감사합니다..! 사실 댓글을 봐도 이해가 잘 안되서 (비전공자의 한계인가봐요ㅠㅠ)
    그래 우선 좀, 클래스부터 제대로 알고 다시 심호흡하고 읽어봐야겠어 해서
    네이버나 생활코딩, 점프투파이썬 같은 곳 찾아보며 나름대로 정리해봤는데!
    도움은 안되시겠지만 링크는 https://www.evernote.com/shard/s196/sh/97b1beca-a799-48ed-8f0f-ef36b8355b28/d0d308fa4b34861c7e7ba04465877deb 이에요!

    그렇게 정리하고 다시 집가면서 댓글 보니까 좀 알 것만도 같아요
    찾아보니까 파이썬만의 특수한 언어 특징(?) 때문에 있는 개념같은데
    아직 다른 언어와의 차이도 잘 몰라서...! 나중에 한 번 더 읽어보려구요 감사합니다:)


티스토리 툴바