#!/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일