import sys
import weakref # weakref 모듈 임포트
class C:
pass
c = C() # 클래스 C의 인스턴스 생성
c.a = 1 # 인스턴스 c에 테스트용 값 설정
print "refcount -", sys.getrefcount(c) # 객체 c의 레퍼런스 카운트 조회
print
d = c # 일반적인 레퍼런스 카운트 증가 방법
print "refcount -", sys.getrefcount(c) # 객체 c의 레퍼런스 카운트 조회
print
r = weakref.ref(c) # 약한 참조 객체 r 생성
print "refcount -", sys.getrefcount(c) # 객체 c의 레퍼런스 카운트 조회 --> 카운트 불변
print
refcount - 2 refcount - 3 refcount - 3
print r # 약한 참조(weakref) 객체
print r() # 약한 참조로 부터 실제 객체를 참조하는 방법: 약한 참조 객체에 함수형태로 호출
print c
print r().a # 약한 참조를 이용한 실제 객체 멤버 참조
print
del c # 객체 제거
del d
print r() # None을 리턴한다
print r().a # 속성도 참조할 수 없다
<weakref at 0x10d83e998; to 'instance' at 0x10d893830> <__main__.C instance at 0x10d893830> <__main__.C instance at 0x10d893830> 1 None
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-17-0a1d693859de> in <module>() 8 del d 9 print r() # None을 리턴한다 ---> 10 print r().a # 속성도 참조할 수 없다 AttributeError: 'NoneType' object has no attribute 'a'
d = {'one': 1, 'two': 2}
wd = weakref.ref(d)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-7-b2a48d12fd2b> in <module>() 1 d = {'one': 1, 'two': 2} ----> 2 wd = weakref.ref(d) TypeError: cannot create weak reference to 'dict' object
import sys
import weakref
class C:
pass
c = C()
c.a = 2
print "refcount -", sys.getrefcount(c) # 객체 c의 레퍼런스 카운트 조회
p = weakref.proxy(c) # 프록시 객체를 만든다
print "refcount -", sys.getrefcount(c) # 객체 c의 레퍼런스 카운트 조회 --> 카운트 불변
print
print p
print c
print p.a
refcount - 2 refcount - 2 <__main__.C instance at 0x10d8a9998> <__main__.C instance at 0x10d8a9998> 2
import weakref
class C:
pass
c = C() # 참조할 객체 생성
r = weakref.ref(c) # weakref 생성
p = weakref.proxy(c) # weakref 프록시 생성
print weakref.getweakrefcount(c) # weakref 개수 조회
print weakref.getweakrefs(c) # weakref 목록 조회
2 [<weakref at 0x10de07c58; to 'instance' at 0x10de06e60>, <weakproxy at 0x10de07ba8 to instance at 0x10de06e60>]
import weakref
class C:
pass
c = C()
c.a = 4
d = weakref.WeakValueDictionary() # WeakValueDictionary 객체 생성
print d
d[1] = c # 실제 객체에 대한 약한 참조 아이템 생성
print d.items() # 사전 내용 확인
print d[1].a # 실제 객체의 속성 참조
del c # 실제 객체 삭제
print d.items() # 약한 사전에 해당 객체 아이템도 제거되어 있음
<WeakValueDictionary at 4526484584> [(1, <__main__.C instance at 0x10dccad40>)] 4 []
class C:
pass
c = C()
c.a = 4
d = {} # 일반 사전 객체 생성
print d
d[1] = c # 실제 객체에 대한 일반 참조 아이템 생성
print d.items() # 사전 내용 확인
print d[1].a # 실제 객체의 속성 참조
del c # 객체 삭제 (사전에 해당 객체의 레퍼런스가 있으므로 객체는 실제로 메모리 해제되지 않음)
print d.items() # 일반 사전에 해당 객체 아이템이 여전히 남아 있음
{} [(1, <__main__.C instance at 0x10d893878>)] 4 [(1, <__main__.C instance at 0x10d893878>)]
I = iter([1,2,3])
print I
print I.next()
print I.next()
print I.next()
print I.next()
<listiterator object at 0x102648cd0> 1 2 3
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-20-98af67aeb8bc> in <module>() 5 print I.next() 6 print I.next() ----> 7 print I.next() StopIteration:
def f(x):
print x + 1
for x in [1,2,3]:
f(x)
2 3 4
def f(x):
print x + 1
t = iter([1,2,3])
while 1:
try:
x = t.next()
except StopIteration:
break
f(x)
2 3 4
def f(x):
print x + 1
t = iter([1,2,3])
for x in t:
f(x)
2 3 4
def f(x):
print x + 1
for x in iter([1,2,3]):
f(x)
2 3 4
def f(x):
print x + 1
for x in iter((1,2,3)):
f(x)
2 3 4
class Seq:
def __init__(self, fname):
self.file = open(fname)
#def __getitem__(self, n):
# if n == 10:
# raise StopIteration
# return n
def __iter__(self):
return self
def next(self):
line = self.file.readline() # 한 라인을 읽는다.
if not line:
raise StopIteration # 읽을 수 없으면 예외 발생
return line # 읽은 라인을 리턴한다.
s = Seq('readme.txt') # s 인스턴스가 next() 메소드를 지니고 있으므로 s 인스턴스 자체가 반복자임
for line in s: # 우선 __iter__() 메소드를 호출하여 반복자를 얻고, 반복자에 대해서 for ~ in 구문에 의하여 next() 메소드가 호출됨
print line,
print
print Seq('readme.txt')
print list(Seq('readme.txt')) # list() 내장 함수가 객체를 인수로 받으면 해당 객체의 반복자를 얻어와 next()를 매번 호출하여 각 원소를 얻어온다.
print tuple(Seq('readme.txt')) # tuple() 내장 함수가 객체를 인수로 받으면 해당 객체의 반복자를 얻어와 next()를 매번 호출하여 각 원소를 얻어온다.
abc def ghi <__main__.Seq instance at 0x10ddc5680> ['abc\n', 'def\n', 'ghi\n'] ('abc\n', 'def\n', 'ghi\n')
d = {'one':1, 'two':2, 'three':3, 'four':4, 'five':5}
for key in d:
print key, d[key]
four 4 three 3 five 5 two 2 one 1
d = {'one':1, 'two':2, 'three':3, 'four':4, 'five':5}
for key in iter(d):
print key, d[key]
four 4 three 3 five 5 two 2 one 1
for key in d.iterkeys(): # 키에 대한 반복자, d.iterkeys() 가 반환한 반복자에 대해 next() 함수가 순차적으로 불리워짐
print key,
four three five two one
keyset = d.iterkeys()
print keyset.next() # 반복자 객체는 항상 next() 메소드를 지니고 있음
for key in keyset: # keyset 반복자에 대해 next() 메소드가 순차적으로 호출됨
print key,
four three five two one
for value in d.itervalues(): # 값에 대한 반복자
print value,
4 3 5 2 1
for key, value in d.iteritems(): #(키,값)에 대한 반복자
print key, value
four 4 three 3 five 5 two 2 one 1
f = open('readme.txt')
print "f.next()", f.next()
for line in f: # f.next() 가 순차적으로 호출됨
print line,
f.next() 1: Hello World 2: Hello World 3: Hello World 4: Hello World 5: Hello World
발생자(Generator)
아래 함수 f()는 자신의 인수 및 내부 변수로서 a, b, c, d를 지니고 있다.
발생자는 f()와 같이 함수가 종료될 때 메모리에서 해제되는 것을 막고 다시 함수가 호출 될 때 이전에 수행이 종료되었던 지점 부터 계속 수행이 가능하도록 구현된 함수이다.
def f(a,b):
c = a * b
d = a + b
return c, d
def generate_ints(N):
for i in range(N):
yield i
gen = generate_ints(3) # 발생자 객체를 얻는다. generate_ints() 함수에 대한 초기 스택 프레임이 만들어지나 실행은 중단되어 있는 상태임
print gen
print gen.next() # 발생자 객체는 반복자 인터페이스를 가진다. 발생자의 실행이 재개됨. yield에 의해 값 반환 후 다시 실행이 중단됨
print gen.next() # 발생자 실행 재개. yield에 의해 값 반환 후 다시 중단
print gen.next() # 발생자 실행 재개. yield에 의해 값 반환 후 다시 중단
print gen.next() # 발생자 실행 재개. yield에 의해 더 이상 반환할 값이 없다면 StopIteration 예외를 던짐
<generator object generate_ints at 0x10ddd6410> 0 1 2
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-8-65149ac25109> in <module>() 4 print gen.next() # 발생자 실행 재개. yield에 의해 값 반환 후 다시 중단 5 print gen.next() # 발생자 실행 재개. yield에 의해 값 반환 후 다시 중단 ----> 6 print gen.next() # 발생자 실행 재개. yield에 의해 더 이상 반환할 값이 없다면 StopIteration 예외를 던짐 StopIteration:
for i in generate_ints(5):
print i,
0 1 2 3 4
print [k for k in range(100) if k % 5 == 0]
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
a = (k for k in range(100) if k % 5 == 0)
print a
print a.next()
print a.next()
print a.next()
for i in a:
print i,
<generator object <genexpr> at 0x10d84df50> 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95
print sum((k for k in range(100) if k % 5 == 0))
950
def fibonacci(a = 1, b = 1):
while 1:
yield a
a, b = b, a + b
for k in fibonacci(): # 발생자를 직접 for ~ in 구문에 활용
if k > 100:
break
print k,
1 1 2 3 5 8 13 21 34 55 89
class Odds:
def __init__(self, limit = None): # 생성자 정의
self.data = -1 # 초기 값
self.limit = limit # 한계 값
def __iter__(self): # Odds 객체의 반복자를 반환하는 특수 함수
return self
def next(self): # 반복자의 필수 함수
self.data += 2
if self.limit and self.limit <= self.data:
raise StopIteration
return self.data
for k in Odds(20):
print k,
print
print list(Odds(20)) # list() 내장 함수가 객체를 인수로 받으면 해당 객체의 반복자를 얻어와 next()를 매번 호출하여 각 원소를 얻어온다.
1 3 5 7 9 11 13 15 17 19 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
def odds(limit=None):
k = 1
while not limit or limit >= k:
yield k
k += 2
for k in odds(20):
print k,
print
print list(odds(20)) # list() 내장 함수가 발생자를 인수로 받으면 해당 발생자의 next()를 매번 호출하여 각 원소를 얻어온다.
1 3 5 7 9 11 13 15 17 19 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
참고 문헌: 파이썬(열혈강의)(개정판 VER.2), 이강성, FreeLec, 2005년 8월 29일