#!/usr/bin/env python
# coding: utf-8
# ***
# ***
# # 19. 클래스와 객체
# ***
# ***
# ***
# ## 1 파이썬 클래스와 이름 공간
# ***
# - 파이썬 클래스는 새로운 이름 공간을 지원하는 또 다른 단위
# - 클래스 정의 구문
# > class 클래스 이름: #헤더(Header)
# > pass #몸체(Body)
# - 인스턴스: 클래스로 부터 만들어낸 객체
# - 모듈 vs. 클래스 vs. 인스턴스
# - 모듈: 파일 단위로 이름 공간을 구성
# - 클래스: 클래스 영역 내에 이름 공간을 구성
# - 인스턴스: 인스턴스 영역 내에 이름 공간을 구성
# In[1]:
class S1:
a = 1
print S1.a
print
S1.b = 2 # 클래스 이름 공간에 새로운 이름의 생성
print S1.b
print
print dir(S1) # S1에 포함된 이름들을 리스트로 반환
del S1.b # 이름 공간 S1에서 b삭제
print dir(S1)
# - 파이썬에서는 동적으로 인스턴스 외부에서 인스턴스 멤버를 추가할 수 있음
# - 파이썬에서는 클래스와 독립적으로 각 인스턴스를 하나의 이름 공간으로 취급함
# In[2]:
x = S1() # x는 S1의 클래스 인스턴스
print x.a
x.a = 10 # 클래스 인스턴스 x의 이름 공간에 이름 생성
print x.a
print S1.a # 클래스 이름 공간과 클래스 인스턴스의 이름공간은 다르다
# In[3]:
y = S1() # S1 클래스의 또 다른 인스턴스 생성
y.a = 300 # 클래스 인스턴스 y의 이름 공간에 이름 생성
print y.a
print x.a # x 인스턴스 공간의 이름 a 확인
print S1.a # 클래스 이름 공간의 a 확인
# In[4]:
class Simple:
pass
s1 = Simple()
s2 = Simple()
# In[5]:
s1.stack = [] # 동적으로 클래스 인스턴스 이름 공간 안에 새로운 변수(이름) stack 생성
s1.stack.append(1) # 값 추가
s1.stack.append(2)
s1.stack.append(3)
print s1.stack
print s1.stack.pop()
print s1.stack.pop()
print
print s1.stack # 최종 s1.stack값
print s2.stack # s2에는 stack을 정의한 적이 없다.
# ![inheritance](https://raw.githubusercontent.com/bluebibi/python-e-learning/master/images/instance.png)
# In[6]:
del s1.stack # s1에서 stack삭제
# ***
# ## 2 메쏘드의 정의와 호출
# ***
# ### 2-1 일반 메쏘드의 정의와 호출
# - 클래스 내부에 메소드 선언 - def 키워드 사용
# - 일반 함수와 다른 점은 첫번째 인수로 self 사용 (self라는 이름은 관례적)
# - self: 인스턴스 객체 자신의 레퍼런스를 지니고 있음
# - 각 인스턴스들은 self를 이용하여 자신의 이름 공간에 접근
# In[7]:
class MyClass:
def set(self, v):
self.value = v
def get(self):
return self.value
# - 인스턴스 객체를 통하여 메소드를 호출할 때 self 인자는 없다고 생각
# In[8]:
c = MyClass() # 인스턴스 생성
c.set('egg') # 메소드 set 호출
print c.get() # 메소드 get 호출
print c.value # 인스턴스 변수에 직접 접근
# - 위 코드는 실제로 아래 코드와 동일함
# In[9]:
c = MyClass() # 인스턴스 생성
MyClass.set(c, 'egg')
print MyClass.get(c)
print c.value
# In[10]:
class Simple:
pass
c = MyClass()
s1 = Simple()
MyClass.set(s1, 'egg') # 다른 클래스의 인스턴스를 넣어주면 에러 발생
# - 메소드 호출 종류
# - Unbound method call: 클래스 객체를 이용한 메소드 호출
# - 예: MyClass.set(c, 'egg')
# - Bound method call: 인스턴스 객체를 통한 메소드 호출 (self 인자는 호출받은 객체가 자동으로 할당)
# - 예: c.set('egg')
# ### 2-2 클래스 내부에서의 메쏘드 호출
# In[11]:
class MyClass:
def set(self, v):
self.value = v
def incr(self):
self.set(self.value + 1) # 내부 메소드 호출
def get(self):
return self.value
c = MyClass()
c.set(1)
print c.get()
print
c.incr()
print c.get()
# - 만약 위 코드에서 self.set(self.value + 1)를 set(self.value + 1)으로 바꾸면 set 함수를 클래스 외부에서 찾는다.
# In[21]:
def set(i):
print "set function outside function - ", i
class MyClass:
def set(self, v):
self.value = v
def incr(self):
set(self.value + 1) # 클래스 외부에 존재하는 set 메소드 호출
def get(self):
return self.value
c = MyClass()
c.set(1)
print c.get()
print
c.incr()
print c.get()
# ### 2-3 정적 메소드(static method)
# - 정적 메소드: 인스턴스 객체와 무관하게 클래스 이름 공간에 존재하는 메소드로서 클래스 이름을 이용하여 직접 호출할 수 있는 메소드
# - [주의] 해당 클래스의 인스턴스를 통해서도 호출 가능
# - 장식자(Decorator) @staticmethod 활용
# In[13]:
class D:
@staticmethod
def spam(x, y): # self가 없다.
print 'static method', x, y
D.spam(1,2) # 인스턴스 객체 없이 클래스에서 직접 호출
print
d = D()
d.spam(1,2) # 인스턴스 객체를 통해서도 호출 가능
# ### 2-4 클래스 메소드(class method)
# - 클래스 메소드: 인스턴스 객체와 무관하게 클래스 이름 공간에 존재하는 메소드로서 클래스 이름을 이용하여 호출하며 첫 인수로 클래스 객체를 자동으로 받는 메소드
# - [주의] 해당 클래스의 인스턴스를 통해서도 호출 가능
# - 장식자(Decorator) @classmethod 활용
# In[31]:
class C:
@classmethod
def spam(cls, y):
print cls, '->', y
print C
C.spam(5) # 첫번째 인수로 C가 잠재적으로 전달된다.
c = C()
c.spam(5) # 인스턴스 객체를 통해서도 호출 가능.
# - 상속받은 서브 클래스를 통해 호출하면, 첫 인수에는 서브 클래스 객체가 자동으로 할당됨
# In[33]:
class D(C):
pass
print D.spam(3)
print
d = D()
print d.spam(3)
print
print C.spam(3)
# ***
# ## 3 클래스 멤버와 인스턴스 멤버
# ***
# - 클래스 멤버 vs. 인스턴스 멤버
# - 클래스 멤버
# - 클래스 이름 공간에 생성됨
# - 모든 인스턴스들에 의해 공유됨
# - 인스턴스 멤버
# - 인스턴스 이름 공간에 생성됨
# - 각각의 인스턴스 마다 독립성이 보장됨
# In[16]:
class Var:
c_mem = 100 # 클래스 멤버 정의
def f(self):
self.i_mem = 200 # 인스턴스 멤버 정의
def g(self):
print self.i_mem
print self.c_mem
# In[17]:
print Var.c_mem # 클래스 객체를 통하여 클래스 멤버 접근
v1 = Var() # 인스턴스 v1 생성
print v1.c_mem # 인스턴스를 통하여 클래스 멤버 접근
v1.f() # 인스턴스 멤버 i_mem이 생성됨
print v1.i_mem # 인스턴스 v1을 통하여 인스턴스 멤버 접근
print
v2 = Var() # 인스턴스 v2 생성
print v2.i_mem # 인스턴스 v2에는 아직 f() 호출이 안되어서 i_mem 멤버 없음 ==> 생성자의 필요성
# ![inheritance](images/instance2.png)
# - "인스턴스 이름.멤버 이름"으로 멤버를 참조할 때 멤버의 검색 순서
# - 1) 인스턴스 멤버
# - 2) 인스턴스 멤버가 없다면 클래스 멤버
# In[18]:
print v1.c_mem # 인스턴스 v1을 통해 클래스 멤버 참조
print v2.c_mem # 인스턴스 v2를 통해 클래스 멤버 참조
print
v1.c_mem = 50 # 인스턴스 이름 공간에 c_mem생성
print v1.c_mem # 인스턴스 v1을 통해 인스턴스 멤버 참조
print v2.c_mem # 인스턴스 v2을 통해 클래스 멤버참조 (인스턴스 멤버가 없으므로, 클래스 멤버 참조)
print Var.c_mem # 클래스 멤버참조
# ![inheritance](images/instance3.png)
# ***
# ## 4 생성자와 소멸자
# ***
# - \_\_init__: 생성자 메소드
# - 객체가 생성될 때 자동으로 불리어지는 메소드
# - self 인자가 정의되어야 함
# - \_\_del__: 소멸자 메소드
# - 객체가 소멸 (메모리에서 해제)될 때 자동으로 불리어지는 메소드
# - self 인자가 정의되어야 함
# - 개발자가 특별히 작성하지 않아도 될 메소드
# - 이유: 파이썬에서는 메모리나 기타 자원들의 해제가 자동으로 되기 때문에
# - [참고] \_\_ (연속된 두 개의 언더라인)의 의미: 예약된 이름
# - 다음 코드에 대한 설명
# - mylife = Life() 로서 인스턴스 mylife가 생성되는 순간 \_\_init__ 생성자 메소드 호출
# - sleep(3)에 의해 3초간 sleep 상태
# - 3초 이후 함수가 리턴됨 --> 로컬 변수가 메모리에서 해제됨 --> \_\_del__ 소멸자 메소드 호출
# In[34]:
# _*_ coding:utf-8 _*_
from time import ctime, sleep
class Life:
def __init__(self): # 생성자
self.birth = ctime() # 현재시간에 대한 문자열을 얻는다.
print 'Birthday', self.birth # 현재 시간 출력
def __del__(self): # 소멸자
print 'Deathday', ctime() # 소멸 시간 출력
def test():
mylife = Life()
print 'Sleeping for 3 sec'
sleep(3) #3초간 sleep(block)상태에 있음 (CPU 점유 못함)
test()
# - 인자를 받는 생성자 호출 가능
# - [참고] \_\_str\_\_: print 예약어나 str() 내장함수 호출에 대응되는 메소드
# In[38]:
class Integer:
def __init__(self, i):
self.i = i
def __str__(self):
return str(self.i)
i = Integer(10)
print i
print str(i)
#
참고 문헌: 파이썬(열혈강의)(개정판 VER.2), 이강성, FreeLec, 2005년 8월 29일