본문 바로가기
코드/python

파이썬 클래스 관련

by WeZZ 2012. 1. 8.

1) 클래스

클래스(class)라는 것은 함수나 변수들을 모아놓은 집합체이다. 하지만 단순한 데이터 자료형이라고 하기엔 그 활용도가 무궁무진하다고 할 수 있다. 클래스를 어떻게 설계하고 그 관계를 어떻게 설정하는가에 의해서 복잡한 것을 단순하게 불분명한것을 명확하게 바꿀 수 있는 능력을 발휘하기도 한다.

다음은 파이썬 클래스의 가장 간단한 예이다.

class Simple:
    pass

위의 클래스는 아무런 기능도 갖고 있지 않은 껍질 뿐인 클래스이다. 하지만 이렇게 껍질 뿐인 클래스도 인스턴스(instance)라는 것을 생성하는 기능은 가지고 있다. (인스턴스와 객체는 같은 말이다. 클래스에 의해서 생성된 객체를 인스턴스라고 부른다)


그렇다면 인스턴스는 무엇인가?

인스턴스는 클래스에 의해서 만들어진 객체로 한개의 클래스는 무수히 많은 인스턴스를 만들어 낼 수가 있다. 위에서 만든 클래스를 이용해서 인스턴스를 만드는 방법은 다음과 같다.

a = Simple()

바로 Simple()의 결과값을 돌려 받은 a가 인스턴스이다. 마치 함수를 사용해서 그 결과 값을 돌려 받는 모습과 비슷하다.


조금 쉽게 이해해 보기

어린시절 뽑기를 해 본적이 있다면 아래 그림과 비슷한 모양의 뽑기 틀을 본적이 있을 것이다. 뽑기 아저씨가 뽑기를 불에 달군 후 평평한 바닥에 "탁"하고 소리나게 떨어뜨려 넙적하고 동그랗게 만든후에 아래와 비슷한 틀로 모양을 찍어준다. 찍어준 모양대로 모양을 만들어 오면 아저씨는 뽑기 한개를 더 해 준다.

이곳에서 설명할 클래스라는 것이 마치 위 뽑기의 틀(별모양, 하트모양)과 비슷하다. 별 모양의 틀(클래스)로 찍으면 별모양의 뽑기( 인스턴스)가 생성되고 하트 모양의 틀( 클래스)로 찍으면 하트모양의 뽑기( 인스턴스)가 나오는 것이다.

클래스란 똑같은 무엇인가를 계속해서 만들어 낼 수 있는 설계도면 같은 것이고(뽑기 틀), 인스턴스란 클래스에 의해서 만들어진 피조물(별 또는 하트가 찍혀진 뽑기)을 뜻하는 것이다.


이야기 형식으로 클래스 기초쌓기

이곳에서는 클래스의 개념을 아직 잡지 못한 독자들을 위한 곳이다. 매우 쉽게 설명하려고 노력하였고 최대한 클래스의 핵심 개념에 근접할 수 있도록 배려를 하였다. 클래스에 대해서 잘 아는 독자라도 재밌게 한 번 읽어 보기를 바란다.


클래스 변수

좀 더 이해를 쉽게 하기 위해서 다음의 클래스를 보자.

>>> class Service:
...     secret = "영구는 배꼽이 두개다."

위의 클래스의 이름은 Service이다. 우리는 위의 Service 클래스를 어떤 유용한 정보를 제공해 주는 한 인터넷 업체라고 해 두자. 이 인터넷 업체는 가입한 고객에게만 유용한 정보를 제공하려 한다. 자 그렇다면 가입을 해야만 이 인터넷 업체의 유용한 정보를 얻을 수 있을 것이다.


가입을 하는 방법은 다음과 같다.

>>> pey = Service()

위 처럼 하면 pey라는 아이디로 인터넷 서비스 업체인 Service클래스를 이용할 수가 있게 된다. 위의 Service 클래스는 마음이 좋아서 돈도 필요 없고 비밀 번호도 필요 없다고 한다.


자 이제 pey라는 아이디로 위 서비스 업체가 제공하는 정보를 얻어내 보자.

>>> pey.secret
"영구는 배꼽이 두 개다"

아이디 이름에다가 서비스 업체가 제공하는 secret라는 변수를 '.'(도트 연산자)를 이용해서 호출하였더니 실로 어마어마한 정보를 얻을 수 있었다.


클래스 함수

하지만 이 Service라는 이름의 인터넷 서비스 제공업체는 신생 벤쳐 기업이라서 위처럼 단 하나만의 정보만을 제공하고 있다고 한다. 하지만 제공해 주는 정보의 양이 너무 적은 듯하여 가입한 사람들을 대상으로 설문조사를 하였더니 모두들 더하기를 잘 못한다고 대답을 했다. 그래서 이 서비스 업체는 더하기를 해주는 서비스를 제공하기로 마음을 먹었다.

두 수를 더하는 서비스를 제공해 주기 위해서 이 서비스 업체는 다음과 같이 클래스를 업그레이드하였다.

>>> class Service:
...     secret = "영구는 배꼽이 두 개다"
...     def sum(self, a, b):
...         result = a + b
...         print "%s + %s = %s 입니다." % (a, b, result)
...
>>>

이제 서비스에 가입한 모든 사람들이 더하기 서비스를 제공받게 되었다.
서비스를 사용하는 방법은 다음과 같았다.


먼저 서비스 업체에 가입을 해서 아이디를 받는다.

>>> pey = Service()


다음에 더하기 서비스를 이용한다.

>>> pey.sum(1,1)
1 + 1 = 2 입니다.


그렇다면 이번에는 서비스 업체의 입장에서 생각해 보도록 하자. 서비스 업체는 오직 가입한 사람들에게만 서비스를 제공하고 싶어한다. 이를 위해서 그들은 더하기 제공하는 서비스에 트릭을 가했다. 위에서 보았던 더하기 해주는 함수를 다시 보면 다음과 같다.

...     def sum(self, a, b):
...         result = a + b
...         print "%s + %s = %s 입니다." % (a, b, result)

누군가 이 서비스 업체의 더하기 서비스를 쓰고 싶다고 요청했을 때 이 사람이 가입을 한 사람인지 안한 사람인지 가리기 위해서 위처럼 sum이라는 함수의 첫 번째 입력 값으로 self라는 것을 집어넣었다.


누군가 다음처럼 더하기 서비스를 이용하려 한다고 생각을 해 보자.

>>> pey = Service()
>>> pey.sum(1, 1)

이렇게 하면 pey라는 아이디를 가진 사람이 이 서비스 업체의 sum이라는 서비스를 이용하겠다고 요청을 한다는 말이다. 위와 같이 했을 때 Service라는 인터넷 제공 업체의 더하기 함수(sum)는 다음처럼 생각한다.

"어 누군가 더하기 서비스를 해 달라고 하네. 그럼 먼저 서비스를 해 주기 전에 이 사람이 가입을 한 사람인지 아닌지 판단해야 겠군. 자 그럼 첫 번째 입력 값으로 뭐가 들어오나 보자. 음... pey라는 아이디를 가진 사람이군. 음, 가입한 사람이군. 서비스를 제공해 주자”


위에서 보듯이 서비스 업체는 sum함수의 첫 번째 입력 값을 통해서 가입 여부를 판단했다. 다시 sum 함수를 보자.

...     def sum(self, a, b):
...         result = a + b
...         print "%s + %s = %s 입니다." % (a, b, result)

위의 sum함수는 첫 번째 입력 값으로 self라는 것을 받고 두 번째 세 번째로 더할 숫자를 받는 함수이다. 위의 sum함수는 입력으로 받는 입력 인수의 갯수가 3개이다.


따라서 pey라는 아이디를 가진 사람은 다음처럼 sum함수를 사용해야 할 것이다.

pey.sum(pey, 1, 1)

sum함수는 첫 번째 입력값을 가지고 가입한 사람인지 아닌지를 판단할 수 있다고 했었다. 따라서 첫 번째 입력 인수로 pey라는 아이디를 주어야지 sum함수는 이 사람이 pey라는 아이디를 가지고 있는 사람임을 알고 서비스를 제공해 줄 것이다. 하지만 위의 sum함수를 호출하는 방법을 보면 pey라는 것이 중복해서 사용되었다.


다음과 같은 문장만으로 sum함수는 이 사람이 pey라는 아이디를 가지고 있음을 알 수 있을 것이다.

>>> pey.sum(1, 1)

그래서 pey.sum(pey, 1, 1)이 아닌 pey.sum(1, 1)이라는 방식을 채택하게 된 것이다. 앞의 방법보다는 뒤의 방법이 쓰기도 쉽고 보기도 쉽지 않은가? pey.sum(1, 1)이라는 호출이 발생하면 self는 호출 시 이용했던 인스턴스(즉, pey라는 아이디)로 바뀌게 된다.


[참고]
self는 사실 다른 언어에서는 찾을 수 없는 파이썬만의 독특한 변수이다. 굳이 왜 'self'가 필요했는지는 파이썬 언어 그 자체를 살펴보아야 한다. 파이썬 언어 개발자가 아닌 우리는 그저 클래스내의 함수의 첫번째 인자는

"무조건 self로 사용을 해야 인스턴스의 함수로 사용할 수 있다."

라고만 알아두자.


self 제대로 알기

시간이 흘러 더하기 서비스를 계속 제공받던 사람들이 똑똑해 졌다고 한다. 그들은 매우 자신감에 넘치게 되어서 매우 잘난 척을 하기에 이르렀고 서비스 업체에 뭔가 색다른 서비스를 제공해 줄 것을 요구하기에 이르렀다. 그 요구는 황당하게도 더하기 서비스를 제공할 때 "홍길동님 1 + 2 = 3 입니다.”처럼 "홍길동” 이라는 자신의 이름을 넣어달라는 것이었다.

인터넷 서비스 업체인 Service는 가입자들의 요구가 참 우스웠지만 그래도 자신의 서비스를 이용해 주는 것에 고마운 마음으로 그러한 서비스를 제공해 주기로 마음을 먹었다.

그래서 다음과 같이 또 Service 클래스를 업그레이드 하게 되었다. 이름을 입력받아서 sum함수를 제공할 때 앞부분에 그 이름을 넣어 주기로 했다.

>>> class Service:
...     secret = "영구는 배꼽이 두 개다"
...     def setname(self, name):
...         self.name = name
...     def sum(self, a, b):
...         result = a + b
...         print "%s님 %s + %s = %s입니다." % (self.name, a, b, result)
...
>>>

그리고 바뀐 점과 사용법에 대해서 가입한 사람들에게 일러주었다. 그래서 사람들은 다음처럼 위의 서비스를 이용할 수 있었다.


먼저 서비스에 가입을 해서 pey라는 아이디를 얻는다.

>>> pey = Service()


다음에 pey라는 아이디를 가진 사람의 이름이 "홍길동”임을 서비스에 알려준다.

>>> pey.setname("홍길동”)


다음에 더하기 서비스를 이용한다.

>>> pey.sum(1, 1)
홍길동님 1 + 1 = 2 입니다.


이제 서비스를 제공해 주는 서비스 업체의 입장에서 다시 한번 생각해 보도록 하자. 우선 이름을 입력 받는 함수 setname을 보자.

...     def setname(self, name):
...         self.name = name


아래처럼 pey라는 아이디를 부여 받은 사람이

>>> pey = Service()


이름을 설정하겠다는 요구를 다음과 같이 하였다.

>>> pey.setname("홍길동")


위와 같은 상황이 발생 했을 때 서비스 제공 업체의 setname함수는 다음과 같이 생각한다.

"pey라는 아이디를 가진 사람이 자신의 이름을 '홍길동'으로 설정하려고 하는 구나. 그렇다면 앞으로 pey라는 아이디로 접근하면 이 사람의 이름이 '홍길동'이라는 것을 잊지 말아야 겠다.”

위와 같은 것을 가능하게 해 주는 것이 바로 self이다.


일단 pey라는 아이디를 가진 사람이 "홍길동”이라는 이름을 setname함수에 입력으로 주면 다음의 문장이 수행된다.

self.name = name


self는 첫 번째 입력 값으로 pey라는 아이디를 받게 되므로 다음과 같이 바뀔 것이다.

pey.name = name


name은 두 번째로 입력받은 "홍길동"이라는 값이므로 위의 문장은 다시 다음과 같이 바뀔 것이다.

pey.name = "홍길동"

위의 말의 의미는 pey라는 아이디를 가진 사람의 이름은 이제 항상 "홍길동”이다 라는 말이다. 이제 아이디 pey에 그 사람의 이름을 부여하는 과정이 끝이 났다.


다음으로 "홍길동님 1 + 1 = 2 입니다.” 라는 서비스를 가능하게 해 주기 위한 더하기 함수를 보도록 하자.

...     def sum(self, a, b):
...         result = a + b
...         print "%s님 %s + %s = %s입니다." % (self.name, a, b, result)

"1 + 1 = 2 입니다.” 라는 서비스만을 제공했던 이전의 sum함수와 비교해 보면 다른 점은 단 하나, self.name이라는 것을 출력 문자열에 삽입한 것 뿐이다. 그렇다면 self.name은 무엇일까? 설명하기 전에 sum함수를 이용하기 까지의 과정을 먼저 보자.


pey라는 이름의 아이디를 가진 사람이 자신의 이름을 "홍길동"이라고 설정한 다음에 sum함수를 다음과 같이 쓰려고 요청했다고 해 보자.

>>> pey = Service()
>>> pey.setname("홍길동”)
>>> pey.sum(1, 1)


이 때 서비스 업체의 sum함수는 다음과 같이 생각한다.

"pey라는 아이디를 가진 사람이 더하기 서비스를 이용하려 하는군. 가입한 사람이 맞군. 아, 그리고 이 사람의 이름은 어디 보자 '홍길동'이군, 이름을 앞에 넣어 준 다음 결과 값을 돌려주도록 하자.”


여기서 우리가 알아야 할 사항은 "sum함수가 어떻게 pey라는 아이디를 가진 사람의 이름을 알아내게 되었을까?” 이다. 먼저 setname함수에 의해서 "홍길동”이라는 이름을 설정해 주었기 때문에 setname함수에 의해서 pey.name이란 것이 "홍길동”이라는 값을 갖게 된다는 사실을 이미 알아보았다. 따라서 sum함수에서도 self.name은 pey.name으로 치환되기 때문에 sum함수는 pey라는 아이디를 가진 사람의 이름을 알아채게 되는 것이다.


__init__ 이란 무엇인가?

자, 이제 또 시간이 흘러 가입자 수가 많아지게 되었다. 더하기 해 주는 서비스는 너무 친절하게 서비스를 제공해 주기 때문이었다. 그런데 가끔 이런 문제가 발생한다고 항의 전화가 빗발치듯 들어온다. 그 사람들의 말을 들어보면 다음과 같은 것이다.

>>> babo = Service()
>>> babo.sum(1, 1)

위와 같이 하면 babo.setname("나바보”)와 같은 과정이 빠졌기 때문에 에러가 나는 것이라고 골백번 얘기를 하지만 항상 이런 실수를 하는 사람들로부터 항의 전화가 와서 서비스 업체에서는 여간 귀찮은 게 아니었다. 그래서 다음과 같은 아이디어를 떠올렸다. 지금까지는 사람들이 서비스 가입 시 바로 아이디를 주는 방식이었는데 아이디를 줄 때 그 사람의 이름을 입력받아야만 아이디를 주는 방식으로 바꾸면 babo.setname("나바보")와 같은 과정을 생략할 수 있을 거란 생각이었다.

위와 같이 해주기 위한 방법을 찾던 중 서비스 업체의 실력자 한사람이 __init__이란 함수를 이용하자고 제의를 한다. 그 방법은 다음과 같았다.

>>> class Service:
...     secret = "영구는 배꼽이 두 개다"
...     def __init__(self, name):
...         self.name = name
...     def sum(self, a, b):
...         result = a + b
...         print "%s님 %s + %s = %s입니다." % (self.name, a, b, result)
...
>>>

위의 Service클래스를 이전의 클래스와 비교해 보면 바뀐 부분은 딱 한가지이다. 바로 setname함수의 이름인 setname이 __init__으로 바뀐 것이다. 클래스에서 이 __init__이란 함수는 특별한 의미를 갖는다. 의미는 다음과 같다.

"인스턴스를 만들 때 항상 실행된다.” 즉, 아이디를 부여받을 때 항상 실행된다는 말이다.


따라서 이제는 위의 서비스에 가입을 하기 위해서 다음처럼 해야 한다.

>>> pey = Service("홍길동”)

이전에는 pey = Service()만을 하면 되었지만 이제는 __init__함수 때문에 pey = Service("홍길동”)처럼 아이디를 부여받을 때 이름 또한 써 주어야 한다.


이전에 했던 방식은 다음과 같다.

>>> pey = Service()
>>> pey.setname("홍길동”)
>>> pey.sum(1, 1)


이것이 __init__ 함수를 이용하면 다음처럼 간략하게 쓸 수 있게 된다.

>>> pey = Service("홍길동”)
>>> pey.sum(1, 1)

따라서 빗발치던 항의 전화도 멈추게 되고 세 번 입력하던 것을 두 번만 입력하면 되니 모두들 기뻐하게 되었다고 한다.

이상과 같이 인스턴스와 self의 의미를 알기 위해서 이야기 형식으로 클래스에 대해서 알아보았다. 위의 내용은 클래스에 대한 정확한 설명이 아니지만 초보자가 인스턴스와 self의 의미, 그리고 __init__함수의 의미를 보다 쉽게 접근할 수 있었을 것이다. 위에서 알아본 pey = Service()로 해서 생성된 pey를 아이디라고 하였는데 이것이 바로 인스턴스라고 불리우는 것임을 잊지 말자.

이제 위에서 알아보았던 기초적인 사항을 바탕으로 클래스에 대해서 자세하게 알아보기로 하자.


클래스 자세히 알기

클래스란 함수나 변수 등을 포함하고 있는 집합체이다. 클래스의 함수는 일반적인 함수와는 다르게 매우 다양한 용도로 쓰일 수도 있다. 클래스는 프로그래머가 설계를 하는 것이다. 마치 함수를 만드는 것과 마찬가지로 프로그래머는 클래스를 만든다. 클래스를 이용하면 전역 변수를 쓸 필요가 없어서 좋고 클래스에 의해서 만들어지는 인스턴스(Instance)라는 것을 중심으로 프로그램을 작성할 수 있기 때문에 객체중심의 독립적인 프로그래밍을 할 수 있게 된다.

클래스란 인스턴스(Instance)를 만들어 내는 공장과도 같다. 이 인스턴스를 어떻게 사용할 수 있는지를 알려면 클래스의 구조를 보면 알 수 있다. 즉, 클래스는 해당 인스턴스의 청사진(설계도)라고 할 수 있다. 사실 지금껏 알아온 자료형, 제어문, 함수들만으로도 우리가 원하는 프로그램을 작성하는데는 문제가 없다. 하지만 클래스를 이용하면 보다 아름답게 프로그램을 만들 수 있게 된다.

이제부터 객체지향 프로그래밍의 가장 중심이 되는 클래스에 대해서 자세히 알아보기로 하자. 아마도 2장에서 가장 어려운 부분이 될 것이다. 잘 이해가 안되더라도 낙심하지는 말자. 파이썬에 익숙해지다 보면 반드시 쉽게 이해가 될 것이다.

여러 가지 클래스를 만들어 보면서 클래스에 대해서 자세히 알아보도록 하자.


클래스의 구조

클래스는 다음과 같은 모습이다.

class 클래스이름[(상속 클래스명)]:
    <클래스 변수 1>
    <클래스 변수 2>
    ...
    def 클래스함수1(self[, 인수1, 인수2,,,]):
        <수행할 문장 1>
        <수행할 문장 2>
        ...
    def 클래스함수2(self[, 인수1, 인수2,,,]):
        <수행할 문장1>
        <수행할 문장2>
        ...
    ...

위에서 보듯이 class라는 명칭은 클래스를 만들 때 쓰이는 예약어이고 그 바로 뒤에는 클래스이름을 써 주어야 한다. 마치 함수에서와 같은 방식이다. 클래스 이름 뒤에 상속할 클래스가 있다면 상속할 클래스 이름을 쓴다. 클래스 내부에는 클래스 변수가 있고 클래스 함수들이 있다.

클래스가 무엇인지 감이 안 오더라도 걱정하지 말고 차근차근 다음의 예를보며 이해해 보자.


사칙연산 하는 클래스 만들기

사칙연산을 쉽게 해주는 클래스를 만들어 볼 것이다. 이 것을 알아보는 과정을 통해서 독자는 클래스를 만드는 방법에 대해서 알게 될 것이다. 우선 사칙연산이란 것은 더하기, 빼기, 나누기, 곱하기를 말한다. 따라서 우리가 만들 클래스는 이러한 기능을 가능하게 만들 것이다.


FourCal이란 사칙연산을 가능하게 하는 클래스가 다음처럼 동작한다고 가정하자. 먼저 a = FourCal()처럼해서 a라는 인스턴스를 만든다.

>>> a = FourCal()


다음에 a.setdata(4, 2)처럼해서 4와 2라는 숫자를 a라는 인스턴스에 지정해 주고

>>> a.setdata(4, 2)


a.sum()을 하면 두 수의 합한 결과(4 + 2)를 돌려주고

>>> print a.sum()
6


a.mul()하면 두수의 곱한 결과(4 * 2)를 돌려주고

>>> print a.mul()

8


a.sub()은 두 수를 뺀 결과(4 - 2)를 돌려주고

>>> print a.sub()
2


a.div()는 두 수를 나눈 결과(4 / 2)를 돌려준다.

>>> print a.div()
2


위와 같은 동작을 하게 만든는 FourCal이란 클래스를 만드는 것이 우리의 목표가 될 것이다.

※ 참고 - 위와 같은 방식은 클래스를 먼저 만드는 것이 아니라 클래스에 의해서 만들어진 인스턴스를 중심으로 어떤 식으로 동작하게 할 것인지 미리 구상을 해 보는 방식이다. 그리고 생각했던 것을 하나씩 해결해 나가면서 클래스를 완성하게 된다. 위의 방법은 필자가 즐겨 사용하는 방법으로 클래스에 의해서 생성된 인스턴스가 어떻게 행동할지 미리 생각한 다음 실제적인 클래스를 만들어 가능 방식이다.


자! 그렇다면 위처럼 동작하는 클래스를 지금부터 만들어 보자. 제일 먼저 할 일은 a = FourCal()처럼 인스턴스를 만들 수 있게 해야 한다. 이것은 매우 간단하다. 다음을 따라해 보자.

>>> class FourCal:
...     pass
...
>>>


우선 대화형 인터프리터에서 위와 같이 pass란 문장만을 포함한 FourCal이란 클래스를 만든다. 위의 클래스는 아무런 변수나 함수도 포함하지 않지만 우리가 원하는 a = FourCal()로 인스턴스 a를 만들 수 있는 기능을 가지고 있다. 확인 해보자.

>>> a = FourCal()
>>> type(a)
<type 'instance'>

위에서 보듯이 a = FourCal()처럼해서 a라는 인스턴스를 먼저 만들고 그 다음에 type(a)로 a라는 변수가 어떤 형태인지 알아보았다. 역시 변수 a가 인스턴스임을 보여준다. (※ 참고 - type함수는 파이썬이 자체적으로 가지고 있는 내장함수로 객체의 종류를 보여준다.)

하지만 우리가 만들어낸 인스턴스 a는 아무런 기능도 가지고 있지 않다. 우리는 더하기, 나누기, 곱하기, 빼기 등의 기능을 가진 인스턴스를 만들어야 한다. 이러한 기능을 갖춘 인스턴스를 만들기 전에 우선적으로 해 주어야 할 일은 a라는 인스턴스에 더하기나 곱하기를 할 때 쓰일 두 개의 숫자를 먼저 부여해 주는 일이다.


다음과 같이 연산을 수행할 대상(4, 2)을 지정할 수 있게 만들어 보자.

>>> a.setdata(4, 2)


위의 사항이 가능하도록 하기 위해서는 다음과 같이 해야 한다.

>>> class FourCal:
...     def setdata(self, first, second):
...         self.first = first
...         self.second = second
...
>>>

이전에 만들었던 FourCal클래스에서 pass란 것은 당연히 없어져야 하고 그 대신에 setdata라는 함수를 만들었다. 클래스 내의 함수를 다른 말로 메써드라고도 한다. 어려운 용어이지만 익혀두도록 하자. (즉 setdata라는 함수는 FourCal클래스의 메써드이다. ) 그렇다면 이제 setdata함수에 대해서 자세하게 알아보기로 하자.


보통 우리가 일반적인 함수를 만들 때는 다음과 같이 만든다.

def sum(a, b):
    return a+b


즉 입력 값이 있고 돌려주는 리턴 값이 있다. 클래스 내의 함수도 마찬가지이다. setdata함수를 다시 적어보면 아래와 같다.

def setdata(self, first, second): 
    self.first = first
    self.second = second

입력 인수로 self, first, second이란 세 개의 입력 값을 받는다. 하지만 일반적인 함수와는 달리 클래스 내의 함수에서 첫 번째 입력 인수는 특별한 의미를 갖는다. 위에서 보면 바로 self가 특별한 의미를 갖는 변수이다.


다음의 예를 보면서 자세히 알아 보기로 하자.

>>> a = FourCal()
>>> a.setdata(4, 2)

위에서 보는 것처럼 a라는 인스턴스를 만든 다음에 a.setdata(4,2)처럼 하면 FourCal클래스 의 setdata함수가 호출되고 setdata함수의 첫 번째 인수에는 자동으로 a라는 인스턴스가 입력으로 들어가게 된다.

즉 setdata의 입력 인수는 self, first, second처럼 총 세 개이지만 a.setdata(4,2)처럼 두 개의 입력 값만 주어도 a라는 인스턴스가 setdata함수의 첫 번째 입력을 받는 변수인 self에 대입되게 되는 것이다.

self: 인스턴스 a, first: 4, second: 2


파이썬 클래스에서 가장 헷갈리는 부분이 바로 이 부분이다. setdata라는 함수는 입력 인수로 3개를 받는데 왜 a.setdata(4,2)처럼 두 개만을 주어도 되는가? 라는 부분이다. 이것에 대한 답변을 여러분은 이제 알았을 것이다.


그 다음으로 중요한 다음의 사항을 보자.

setdata 함수에는 두 개의 수행할 문장이 있다.

self.first = first
self.second = second

이것이 뜻하는 바에 대해서 알아보자. 입력인수로 받은 first는 4이고 second는 2라는 것은 이미 알아 보았다.


그렇다면 다음과 같이 위의 문장은 다음과 같이 바뀔 것이다.

self.first = 4
self.second = 2

여기서 중요한 것은 바로 self이다. self는 a.setdata(4, 2)처럼 호출했을 때 자동으로 첫 번째 입력 인수로 들어오는 인스턴스 a라고 했다. 그렇다면 self.first의 의미는 무엇이겠는가? 당연히 a.first가 될 것이다. self.second는 당연히 a.second가 될 것이다.


따라서 위의 두 문장을 풀어서 쓰면 다음과 같이 될 것이다.

a.first = 4
a.second = 2


정말 이런지 확인 해 보도록 하자.

>>> a = FourCal()
>>> a.setdata(4, 2)
>>> print a.first
4
>>> print a.second
2


지금껏 완성된 클래스를 다시 써보면 다음과 같다.

>>> class FourCal:
...     def setdata(self, first, second):
...         self.first = first
...         self.second = second
...
>>>

지금까지 한 내용이 바로 위의 4줄을 설명하기 위한 것이었다. 위에서 설명한 것들이 이해가 잘 되지 않는다면 다시 한번 읽어보는 것이 좋다. 지금껏 했던 것을 이해하지 못하면 다음에 할 것들도 이해하기가 어렵기 때문이다. 자! 그럼 이제 두 개의 숫자 값을 설정해 주었으니 두 개의 숫자를 더하는 기능을 위의 클래스에 추가해 보도록 하자.


우리는 다음과 같이 더하기를 할 수 있는 기능을 갖춘 클래스를 만들어야 한다.

>>> a = FourCal()
>>> a.setdata(4, 2)
>>> print a.sum()
6


위의 것을 가능하게 하기 위해서 FourCal클래스를 다음과 같이 만들어야 한다.

>>> class FourCal:
...     def setdata(self, first, second):
...         self.first = first
...         self.second = second
...     def sum(self):
...         result = self.first + self.second
...         return result
...
>>>


추가된 것은 sum이란 함수이다. 이 함수만 따로 떼어내서 생각해 보도록 하자.

def sum(self):
    result = self.first + self.second
    return result

입력으로 받는 값은 self밖에 없고 돌려주는 값은 result이다. a.sum()처럼 하면 sum함수에 자동으로 인스턴스 a가 첫 번째 입력 인수로 들어가게 된다는 것을 명심하자. 따라서 sum함수의 첫 번째 입력 변수 self는 인스턴스 a가 된다.


그러면 이번에는 돌려주는 값을 보자.

result = self.first + self.second


위의 내용은 아래와 같이 해석 될 것이다.

result = a.first + a.second


위의 내용은 a.setdata(4, 2)에서

a.first = 4
a.second = 2


라고 이미 설정되었기 때문에 다시 다음과 같이 해석 될 것이다.

result = 4 + 2


따라서

>>> print a.sum()

위처럼 하면 6이란 값을 화면에 출력하게 한다.


여기까지 모두 이해한 독자라면 클래스에 대한 것 80% 이상을 알았다고 보아도 된다. 파이썬의 클래스는 그다지 어렵지 않다.


그렇다면 이번에는 곱하기, 빼기, 나누기 등을 할 수 있게 해보자.

>>> class FourCal:
...     def setdata(self, first, second):
...         self.first = first
...         self.second = second
...     def sum(self):
...         result = self.first + self.second
...         return result
...     def mul(self):
...         result = self.first * self.second
...         return result
...     def sub(self):
...         result = self.first - self.second
...         return result
...     def div(self):
...         result = self.first / self.second
...         return result
...
>>>

mul, sub, div모두 sum함수에서 했던 것과 마찬가지 방법이니 따로 설명을 하지는 않겠다.


정말로 모든 것이 제대로 동작하는지 확인해보자.

>>> a = FourCal()
>>> a.setdata(4, 2)
>>> a.sum()
6
>>> a.mul()
8
>>> a.sub()
2
>>> a.div()
2

우리가 목표로 했던 사칙연산을 해내는 클래스를 만들어 낸 것이다.


"박씨네 집” 클래스

이번에는 전혀 다른 내용의 클래스를 한 번 만들어 보자. 사칙 연산을 하는 클래스보다는 조금 재미있게 만들어 보자. "박씨네 집”이라는 클래스를 만들어 보겠다. 먼저 클래스가 어떤 식으로 동작하게 할 지 생각해 보자.


클래스 이름은 HousePark으로 하기로 하자. pey라는 인스턴스를 다음처럼 만든다.

>>> pey = HousePark()


pey.lastname을 출력하면 "박씨네 집”이기 때문에 "박"이라는 성을 출력하게 만들기로 하자.

>>> print pey.lastname


이름을 설정하면 pey.fullname이 성을 포함한 값을 가지게 하도록 만들자.

>>> pey.setname("응용")
>>> print pey.fullname
박응용


travel이란 함수에 여행을 가고 싶은 곳을 입력으로 주면 다음과 같이 출력해 주는 travel함수도 만들어 보자.

>>> pey.travel("부산")
박응용, 부산여행을 가다.


우선 여기까지만 만들어 보기로 하자. 어렵지 않을 것이다. 먼저 인스턴스만 단순히 생성할 수 있는 클래스는 다음처럼 만들 수 있다.

>>> class HousePark:
...     pass
...
>>>


이렇게 하면 pey = HousePark()처럼 해서 인스턴스를 만들어 낼 수 있게 된다. 이번에는 pey.lastname하면 "박"을 출력하게 하기 위해서 다음처럼 해보자.

>>> class HousePark:
...     lastname = "박"
...
>>>


lastname은 클래스 변수이다. 이 클래스 변수 lastname은 HousePark클래스에 의해서 생성되는 인스턴스 모두에 lastname은 "박"이라는 값을 갖게 하는 기능을 한다. 다음의 예를 보자.

>>> pey = HousePark()
>>> pes = HousePark()
>>> print pey.lastname

>>> print pes.lastname

위에서 보듯이 HousePark클래스에 의해서 생긴 인스턴스는 모두 lastname이 "박"으로 설정되는 것을 확인 할 수 있다.

참고 - 클래스 변수를 쓸 수 있는 또 하나의 방법

>>> print HousePark.lastname


다음에는 이름을 설정하고 print pey.fullname하면 성을 포함한 이름을 출력하게 하도록 만들어 보자.

>>> class HousePark:
...     lastname = "박"
...     def setname(self, name):
...         self.fullname = self.lastname + name
...
>>>

우선 이름을 설정하기 위해서 setname이란 함수를 이용하였다.


위의 함수는 다음처럼 사용될 것이다.

>>> pey = HousePark()
>>> pey.setname("응용")

위의 예에서 보듯이 setname함수에 "응용"이란 값을 인수로 주어서 결국 self.fullname에는 "박” + "응용”이란 값이 대입되게 된다.


이 과정을 살펴 보면 다음과 같다.

self.fullname = self.lastname + name


우선 두 번째 입력 값 name 은 "응용” 이므로 다음과 같이 바뀔 것이다.

self.fullname = self.lastname + "응용”


다음에 self는 setname함수의 첫 번째 입력으로 들어오는 pey라는 인스턴스이기 때문에 다음과 같이 다시 바뀔 것이다.

pey.fullname = pey.lastname + "응용"


pey.lastname은 클래스 변수로 항상 "박"이란 값을 갖기 때문에 다음과 같이 바뀔 것이다.

pey.fullname = "박" + ”응용"


따라서 위와 같이 pey.setname("응용”)을 한 다음에는 다음과 같은 결과를 볼 수 있을 것이다.

>>> print pey.fullname
박응용


이제 우리가 만들려고 했던 클래스의 기능 중 단 한가지만 남았다.

"박응용”을 여행 보내게 하는 함수 travel을 HousePark 클래스에 구현해 보자.

>>> class HousePark:
...     lastname = "박"
...     def setname(self, name):
...         self.fullname = self.lastname + name
...     def travel(self, where):
...         print "%s, %s여행을 가다." % (self.fullname, where)
...
>>>

travel이란 함수를 추가시켰다. 입력 값으로 인스턴스와 where를 받는다. 그리고 해당 값들을 문자열 포맷팅 연산자를 이용하여 문자열에 삽입한 후 출력한다.


위의 클래스는 다음과 같이 사용되어 진다.

>>> pey = HousePark()
>>> pey.setname("응용")
>>> pey.travel("부산")
박응용, 부산여행을 가다.


위의 과정을 travel함수의 입장에서 살펴보면 다음과 같다. 우선 travel함수의 입력변수인 self와 where은 다음과 같을 것이다.

self: pey
where : "부산"

따라서 self.fullname은 pey.fullname이 될 것이고 이 pey.fullname은 pey.setname("응용”)에 의해서 만들어진 "박응용”이 될 것이다. 따라서 pey.travel("부산”)처럼 하게 되면 위의 예처럼 출력되게 되는 것이다.


초기값 설정하기

우리는 위에서 HousePark이라는 클래스를 이용해서 인스턴스를 만들었는데 이 인스턴스에 setname함수를 이용해서 이름을 설정해 주는 방식을 사용했었다.


하지만 위에서 만든 함수를 다음과 같이 실행해 보자.

>>> pey = HousePark()
>>> pey.travel("부산”)

에러가 나게 된다. 에러의 이유는 travel함수에서 self.fullname이란 변수를 필요로 하는 데 self.fullname이란 것은 setname이란 함수에 의해서 생성되는 것이기 때문에 위의 경우 setname을 해주는 부분이 생략되어서 에러가 나게 되는 것이다. 클래스 설계시 이렇게 에러가 날 수 있는 상황을 만들면 좋은 클래스라고 보기 어렵다. 따라서 이런 에러가 나는 것을 방지하기 위해서 pey라는 인스턴스를 만드는 순간 setname함수가 동작하게 한다면 상당히 편리할 것이다. 이러한 생각으로 나오게 된 것이 바로 __init__ 이란 함수이다.


__init__ 함수, 초기치를 설정한다.

자 그렇다면 위의 클래스를 다음과 같이 바꾸어 보자.

>>> class HousePark:
...     lastname = "박"
...     def __init__(self, name):
...         self.fullname = self.lastname + name
...     def travel(self, where):
...         print "%s, %s여행을 가다." % (self.fullname, where)
...
>>>

setname함수의 이름이 __init__으로 바뀌기만 하였다.


이것이 어떤 차이를 불러오는지 알아보자. 다음처럼 해보자.

>>> pey = HousePark()
TypeError: __init__() takes exactly 2 arguments (1 given)

위와 같은 에러 메시지를 볼 수 있을 것이다. 에러 메시지의 원인을 보면 입력 인수로 두 개를 받아야 하는데 1개 만 받았다는 에러이다. 여기서 1개를 받았다는 것은 바로 pey라는 인스턴스이다. 자! 에러의 메시지를 보면 알 수 있다. pey = HousePark()이라고 하는 순간 __init__함수가 호출 되게 되는 것이다. 따라서 __init__(self, name)처럼 __init__함수는 두 개의 입력값을 필요로 하게 된다. 그렇다면 어떻게 인스턴스를 만들 때 __init__함수에 두 개의 입력값을 줄 수 있을까?


그것은 다음과 같다.

>>> pey = HousePark("응용")

마치 이전에 보았던 setname함수를 썼던 것과 마찬가지 방법이다. 다만 인스턴스를 생성하는 순간에 입력값으로 "응용"이란 입력값을 주는 점이 다르다. __init__ 함수를 이용하면 만들어지는 인스턴스에 초기값을 줄 수 있기 때문에 편리할 때가 많다.


다음과 같이 하면 에러 없이 잘 실행되는 것을 확인 할 수 있을 것이다.

>>> pey = HousePark("응용")
>>> print pey.travel("태국")
박응용, 태국여행을 가다.


__del__ 함수, 인스턴스가 사라질 때 호출된다.

이번에는 인스턴스가 사라질 때 특정한 행동을 취할 수 있게 하는 방법에 대해서 알아보도록 하자. 인스턴스가 사라진다함은 다음과 같은 경우를 말한다.

>>> pey = HousePark("응용")
>>> del pey

파이썬이 자체적으로 가지고 있는 내장 함수 del에 의해서 pey라는 인스턴스를 소멸시킬 수 있다. 또한 파이썬 프로그램이 다 수행되고 종료될 때 역시 만들어진 인스턴스들이 모두 사라지게 된다.


이렇게 프로그램 내에서 del함수에 의해서 사라지거나 프로그램이 종료될 때 특정한 행동을 취할 수 있도록 클래스를 재구성 해보자.

>>> class HousePark:
...     lastname = "박"
...     def __init__(self, name):
...         self.fullname = self.lastname + name
...     def travel(self, where):
...         print "%s, %s여행을 가다." % (self.fullname, where)
...     def __del__(self):
...         print "%s 죽네" % self.fullname
...
>>>


위와 같이 클래스를 다시 만든 다음에 다음과 같이 따라해 보자.

>>> pey = HousePark("응용")
>>> del pey
박응용 죽네

즉 클래스 내에 사용되는 __del__ 이란 함수는 인스턴스가 사라질 때 호출되는 것임을 확인 할 수 있다.


상 속 (Inheritance)

상속이란 말은 "물려받다” 라는 뜻이다. "재산을 상속받다” 할 때의 상속과 같은 의미이다. 클래스에도 이런 개념을 쓸 수가 있다. 어떤 클래스를 만들 때 다른 클래스의 기능을 상속받을 수 있는 것이다. 우리는 "박씨네 집”이라는 HousePark이라는 클래스를 만들었었는데 이번엔 "김씨네 집”이라는 HouseKim 클래스를 만들어 보자. 상속의 개념을 이용하면 다음과 같이 간단하게 할 수 있다. HousePark클래스는 이미 만들어 놓았다고 가정을 한다. 다음의 예는 HouseKim이라는 클래스가 HousePark클래스를 상속하는 예제이다.

>>> class HouseKim(HousePark):
...      lastname = "김"
...
>>>

성을 "김"으로 고쳐 주었다. 그리고 아무런 것도 추가 시키지 않았다.


이 HouseKim이란 클래스는 위와 같이

class HouseKim(HousePark):

클래스명다음에 괄호안에 다른 클래스를 넣어주면 상속을 하게된다.


위 클래스는 마치 다음처럼 코딩한 것과 완전히 동일하게 동작한다.

>>> class HouseKim:
...     lastname = "김"
...     def __init__(self, name):
...         self.fullname = self.lastname + name
...     def travel(self, where):
...         print "%s, %s여행을 가다." % (self.fullname, where)
...     def __del__(self):
...         print "%s 죽네" % self.fullname
...
>>>

즉, HousePark클래스와 완전히 동일하게 행동하는 것이다.


다시 다음과 같이 HouseKim이라는 클래스를 만들자.

>>> class HouseKim(HousePark):
...      lastname = "김"
...
>>>


그리고 아래와 같이 따라해 보자.

>>> julliet = HouseKim("줄리엣")
>>> julliet.travel("독도")
김줄리엣, 독도여행을 가다.

HousePark클래스의 모든 기능을 상속받았음을 확인할 수 있다. 재미있지 않은가? 상속의 개념을 이용해서 독자는 "양씨네 집”, "이씨네 집”등을 쉽게 만들 수 있을 것이다.


상속의 개념중 하나 더 알아야 할 것이 있는데 그것은 상속대상이 된 클래스의 함수중에서 그 행동을 달리 하고 싶을 때가 있을 것이다. 이럴땐 어떻게 해야 하는 것이까? 우리는 "김씨네 집”이란 클래스가 "박씨네 집”클래스를 상속받았는데 여기서 상속받은 travel함수를 다르게 설정하는 방법을 한번 보도록 하자.

>>> julliet = HouseKim("줄리엣")
>>> julliet.travel("독도", 3)
김줄리엣, 독도여행 3 가네.


위처럼 행동할 수 있게끔 HouseKim 클래스를 만들어 보자.

>>> class HouseKim(HousePark):
...     lastname = "김"
...     def travel(self, where, day):
...         print "%s, %s여행 %d일 가네." % (self.fullname, where, day)
...
>>>

위처럼 travel함수를 다르게 설정하고 싶으면 동일한 이름의 travel함수를 HouseKim 클래스내에서 다시 설정해 주면 된다. 간단하다.


연산자 오버로딩

연산자 오버로딩이란 연산자(+, -, *, /, , , )등을 인스턴스끼리 사용할 수 있게 하는 기법을 말한다. 쉽게 말해서 다음과 같은 것을 가능하게 만드는 것이다.

>>> pey = HousePark("응용")
>>> julliet = HouseKim("줄리엣")
>>> pey + julliet
박응용, 김줄리엣 결혼했네

즉, 인스턴스끼리 연산자 기호를 사용하는 방법을 말하는 것이다.


우선 이미 만들어 보았던 클래스들에 몇가지 사항을 추가하여 에디터를 이용해서 다음처럼 작성해 보자.

# house.py

class HousePark:
    lastname = "박"
    def __init__(self, name):
        self.fullname = self.lastname + name
    def travel(self, where):
        print "%s, %s여행을 가다." % (self.fullname, where)
    def love(self, other):
        print "%s, %s 사랑에 빠졌네" % (self.fullname, other.fullname)
    def __add__(self, other):
        print "%s, %s 결혼했네" % (self.fullname, other.fullname)
    def __del__(self):
        print "%s 죽네" % self.fullname


class HouseKim(HousePark):
    lastname = "김"
    def travel(self, where, day):
        print "%s, %s여행 %d일 가네." % (self.fullname, where, day)

pey = HousePark("응용")
julliet = HouseKim("줄리엣")
pey.love(julliet)
pey + julliet

위의 프로그램을 실행시키면 다음과 같은 결과를 보여 준다.

박응용, 김줄리엣 사랑에 빠졌네
박응용, 김줄리엣 결혼했네
박응용 죽네
김줄리엣 죽네


위의 프로그램의 실행 부분인 다음을 보자.

pey = HousePark("응용")
julliet = HouseKim("줄리엣")
pey.love(julliet)
pey + julliet

먼저 pey = HousePark("응용”)으로 pey라는 인스턴스를 만들고 julliet이라는 인스턴스 역시 하나 생성한다. 다음에 pey.love(julliet)이란 클래스 함수 love가 호출되었다.


love함수를 보면

   def love(self, other):
        print "%s, %s 사랑에 빠졌네" % (self.fullname, other.fullname)

입력 인수로 두 개의 인스턴스를 받는 것을 알 수 있다. 따라서 pey.love(julliet)과 같이 호출하면 self에는 pey가 other에는 julliet이 들어가게 되는 것이다. 따라서 "박응용, 김줄리엣 사랑에 빠졌네"라는 문장을 출력하게 된다.


자! 이제 다음과 같은 문장이다.

pey + julliet

더하기 표시기호인 '+'를 이용해서 인스턴스를 더하려고 시도한다. 이렇게 '+'연산자를 인스턴스에 사용하게 되면 클래스의 __add__ 라는 함수가 호출되게 된다.


HousePark에서 사용된 부분을 보면 다음과 같다.

    def __add__(self, other):  
        print "%s, %s 결혼했네" % (self.fullname, other.fullname)

pey + julliet처럼 호출되면 __add__(self, other) 함수의 self는 pey가 되고 other는 julliet이 된다. 따라서 "박응용, 김줄리엣 결혼했네"라는 문자열을 출력한다.


다음에는 프로그램이 종료하게 되는데 프로그램이 종료될 때 인스턴스가 사라지게 되므로 __del__ 함수가 호출되어 "박응용 죽네”, "김줄리엣 죽네”라는 문자열이 출력되게 되는 것이다.


자, 이젠 지금껏 만들어본 클래스로 이야기를 만들어 보자. 스토리는 다음과 같다.

"박응용은 부산에 놀러가고
김줄리엣도 우연히 3일 동안 부산에 놀러간다.
둘은 사랑에 빠져서 결혼하게 된다.
그러다가 바로 싸우고 이혼을 하게 된다.”


참으로 슬픈 이야기이지만 연산자 오버로딩을 공부하기에 더없이 좋은 이야기이다. 다음처럼 동작시키면

pey = HousePark("응용")
julliet = HouseKim("줄리엣")
pey.travel("부산")
julliet.travel("부산", 3)
pey.love(julliet)
pey + julliet
pey.fight(julliet)
pey - julliet


결과값을 다음과 같이 나오게 만드는 클래스를 작성하는 것이 목표이다.

박응용 부산여행을 가다.
김줄리엣 부산여행 3 가네.
박응용, 김줄리엣 사랑에 빠졌네
박응용, 김줄리엣 결혼했네
박응용, 김줄리엣 싸우네
박응용, 김줄리엣 이혼했네
박응용 죽네
김줄리엣 죽네

위에서 보면 fight라는 함수를 추가시켜야 하고 pey - julliet을 수행하기 위해서 __sub__ 이라는 '-'연산자가 쓰였을 때 호출되는 함수를 만들어 주어야 한다.


자, 최종적으로 만들어진 "박씨네 집” 클래스를 공개한다.

class HousePark:
    lastname = "박"
    def __init__(self, name):
        self.fullname = self.lastname + name
    def travel(self, where):
        print "%s, %s여행을 가다." % (self.fullname, where)
    def love(self, other):
        print "%s, %s 사랑에 빠졌네" % (self.fullname, other.fullname)
    def fight(self, other):
        print "%s, %s 싸우네" % (self.fullname, other.fullname)
    def __add__(self, other):
        print "%s, %s 결혼했네" % (self.fullname, other.fullname)
    def __sub__(self, other):
        print "%s, %s 이혼했네" % (self.fullname, other.fullname)
    def __del__(self):
        print "%s 죽네" % self.fullname


class HouseKim(HousePark):
    lastname = "김"
    def travel(self, where, day):
        print "%s, %s여행 %d일 가네." % (self.fullname, where, day)


pey = HousePark("응용")
julliet = HouseKim("줄리엣")
pey.travel("부산")
julliet.travel("부산", 3)
pey.love(julliet)
pey + julliet
pey.fight(julliet)
pey - julliet


결과값은 예상한 대로 다음처럼 나올 것이다.

박응용, 부산여행을 가다.
김줄리엣, 부산여행 3 가네.
박응용, 김줄리엣 사랑에 빠졌네
박응용, 김줄리엣 결혼했네
박응용, 김줄리엣 싸우네
박응용, 김줄리엣 이혼했네
박응용 죽네 
김줄리엣 죽네


우리가 알아본 것 외에도 오버로딩 기법에 쓰이는 것들이 많이 있다. 다음의 표를 보고 어떤 것들을 사용할 수 있는지 알아보자.

[참고] 클래스내의 함수연산자 언제 호출되나?

함수 설명 예제 (X, Y는 인스턴스)
__init__ 생성자(Constructor), 인스턴스가 만들어 질 때 호출
__del__ 소멸자(Destructor) 인스턴스가 사라질 때 호출

__add__ 연산자 "+" X + Y
__or__ 연산자 "|" X | Y
__repr__ print print X
__call__ 함수호출 X()했을 때 호출
__getattr__ 자격부여 X.메소드
__getitem__ 인덱싱 X[i]
__setitem__ 인덱스 치환 X[key] = value
__getslice__ 슬라이싱 X[i:j]
__cmp__ 비교 X > Y


물론 위의 있는 것들이 전부는 아니다. 이외에도 여러 가지가 있다. 이것들이 필요할 때가 온다면 독자는 이미 상당한 수준의 파이썬 프로그래머일 것이다. 그 때는 직접 레퍼런스를 찾아가며 사용하자. 이제 이러한 연산자 오버로딩이 무엇이며 어떻게 사용해야 하는지 알게 되었을 것이다.


출처 : http://codejob.co.kr/docs/page/56/