[Python] Iterator using yield & db cursor Develop Tip

다음의 간단한 파이썬 코드를 보시지요.

mylist = [0,1,2]
for i in mylist:
print(i*i)

실행하면,
0
1
4

결과가 나옵니다.

일반적으로 위와 같이 Iterable 개체 (리스트, 튜플 등)를 이용하고 있습니다.

혹은 더 고급 방법으로서 generator 를 만드는 방법도 있습니다.

mygen = (x*x for x in range(3))
for i in mygen:
print(i)

해도 동일한 결과가 나옵니다.

마지막으로 yield 를 이용해 보겠습니다.
얼핏 보면 더 길어져 보기 힘들 것 같지만,
(처음 yield를 제대로 이해 못하면 그럴 수 있습니다)
잘 사용하면 참 편한 것이더군요.

def yGen():
for i in range(3):
yield i*i
for i in yGen():
print(i)

위와 같이 for loop 에 들어갈 수 있는 것은, iterable, generator, yield 를 이용한 세 가지 방법이 있습니다.

그럼 간단히 mysql 이나 mariaDB 의 커서를 이용하는 방법을 살펴보면,

####################################################################################################
def paramExecute(cursor, stmt, paramList=None):
"""
@brief for using with parameterized list mysql_db.execute(cursor, paramTuple)
@param cursor [MySQLdb.cursor]
@param stmt [string] statement
@param paramList [list] or tuple parameters list or tuple
@return [int] affected row count
"""
if not paramList:
rc = cursor.execute(stmt)
elif type(paramList).__name__ == 'list':
rc = cursor.execute(stmt, tuple(paramList))
elif type(paramList).__name__ == 'tuple':
rc = cursor.execute(stmt, paramList)
else:
raise Exception('Invalid parameter passing for mysql Statement')
return rc

####################################################################################################
class mySelect(object):
"""
@brief mysql cursor wrapper class
"""
#===============================================================================================
def __init__(self, mdb, stmt, paramList=None):
"""
@brief execute select
@param db [object] mysql instance
@param stmt [string] select statement
@param paramList [list of string] or tuple parameters list or tuple
"""
if mdb is None:
raise ReferenceError('db cannot be None')
self.mdb = mdb
self.mdb.check_timeout()
self.cursor = self.mdb.db.cursor()
paramExecute(self.cursor, stmt, paramList)
# self.cursor.rowcount
# self.cursor.description
#===============================================================================================
def close(self):
if self.cursor is not None:
self.cursor.close()
self.cursor = None
#===============================================================================================
def __enter__(self):
"""
@brief called in enterence of with statement
"""
return self
#===============================================================================================
def __exit__(self, type, value, traceback):
"""
@brief called of exiting of with statement
"""
self.close()
#===============================================================================================
def __del__(self):
"""
@brief destructor check if not used with Context
"""
self.close()
#===============================================================================================
def next_iterator(self):
while True:
rec = self.cursor.fetchone()
if rec is None: break
yield rec
yield None

와 같이 설정하고,

with mySelect(tdb, stmt) as ms:
for rec in ms.next_iterator():
print rec

위와 같은 방법으로 with context manager와 같이 간단하게 cursor의 select fetch를 구현해 볼 수 있습니다.

한가지 더, 염두에 두어야 할 것은 우에서 ms.next_iterator() 의 결과는 iterator 입니다.
따라서, for loop 대신 while loop 을 사용한다면 다음과 같이 하여야 합니다.

with mySelect(tdb, stmt) as ms:
rec_iter = ms.next_iterator():
while True:
rec = rec_iter.next()
if rec is None: break
print rec


어느분께는 도움이 되셨기를...

덧글

댓글 입력 영역

구글애드텍스트