[Python] 큰 파일을 라인단위로 읽어 처리할 때, xreadlines 이용하기 Develop Tip

우선 파이썬 2.7.x 버전을 사용하고 있다고 가정합니다.
파이썬의 range 와 xrange의 차이점을 이해하고 있는 것은 아주 중요합니다.

예를 들어

for i in range(100000000):
    # do something with i
    print i

라고 하면 어떤일이 발생할까요?

for loop을 돌기전,
range는 [0,1,2,...,99999999] 이라는
1억개의 정수 엘리먼트를 가진 리스트를 메모리에 만들어 메모리의 그 리스트를 이용하려고 할 것입니다.
이것은 엄청난 메모리를 사용하고 있습니다.

그런데 다음과 같은 generator가 있다고 하지요.

def x_range(_limit):
    cnt = 0
    while cnt < limit:
        yield cnt
        cnt += 1
for i in x_range(100000000):
    # do something with i
    print i

이번에는 x_range를 부르면 제너레이터에 의하여 미리 리스트를 만들어 놓지 않고
필요시 그 다음 iteration이 돌게 되므로 처음과 같은 메모리에 결과를 넣지
않아도 됩니다.

그래서 파이썬 2.x 에서는 range 대신 xrange 가 존재합니다.
필요에 따라서 리스트 자체를 얻으려고 할 때에는 range 를 이용하면 되겠지요.
파이썬 3.x 에서는 아예 2.x의 range 자체가 xrange 역할의 generator로 이용된다 합니다.
그렇다면 3.x에서는 2.x의 range 와 같은 리스트를 어떻게 구할까요?

mylist = [ x for x in range(1000) ]
과 같이 리스트내포 기능을 이용하면 되겠군요.


자, 이제는 본론으로 돌아와서 파일을 읽어 어떤 작업을 한다고 가정합니다.

with open(f_name) as ifp:
    lines = ifp.read().split('\n')
    for line in lines:
        # do some jobs for line
        print line

위와 같이 있는데 파일 크기가 작을 경우에는 아무런 문제가 되지 않습니다.
그런데 파일이 10GB 와 같은 큰 크기라면 문제가 됩니다.
왜냐하면 ifp.read() 에서 파일의 내용을 모두 읽어 메모리에 보관하려고 하기 때문이지요.

조금 변형된 readlines를 이용해도 되는데요,

with open(f_name) as ifp:
    lines = ifp.readlines()
    for line in lines:
        # do some jobs for line
        print line

역시 ifp.readlines() 에서 파일 내용을 모두 lines 리스트 메모리에 넣어 두려고 하므로
동일한 메모리 문제가 발생합니다.

따라서, 구글링을 해 보면 다음과 같은 코드가 있기도 합니다.

with open(f_name) as ifp:
    while True:
        lines = ifp.readlines(1000)
        if not lines: break
        for line in lines:
            # do some jobs for line
            print line

이제는 파일에서 1000줄씩 읽어 메모리에 넣고 작업을 하므로 파일이 아무리 커도
문제가 되지 않습니다.

그러나...

range와 xrange 의 관계처럼,
위에 ifp.readlines() 대신 ifp.xreadlines() 가 존재하고 있었으니... (2.1 부터 존재했더군요)

with open(f_name) as ifp:
    lines = ifp.xreadlines()
    for line in lines:
        # do some jobs for line
        print line

와 같이 작업하면 됩니다.

그런데 똑 같은 코드이지만 더 작은 코드가 바로!!

with open(f_name) as ifp:
    for line in ifp:
        # do some jobs for line
        print line

즉 iter(ifp) 와 ifp.xreadlines() 는 동일한 generator 라고 하네요.

언어를 이해하면 할 수록 정확한 의미를 알고 사용해야 한다는 것을 느낍니다.


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



덧글

댓글 입력 영역

구글애드텍스트