티스토리 뷰

반응형

표준입력과 input 함수

지난 글에서 파이썬에서 텍스트 파일을 액세스할 때 파일 핸들러를 만들어서 사용한다고 했고, 파일 핸들러는 내부적으로 TextIOWrapper라는 버퍼 객체라고 했다.

input() 내장함수 역시 TextIOWrapper를 사용한다. 대신 열리는 것이 디스크 상의 파일이 아니라 쉘이 제공하는 표준입력이다. TextIOWrapper(name="<stdin>") 과 같은 식으로 만들어지는 버퍼가 있고, 이 버퍼는 표준입력을 파일로 간주하고 한 줄씩 읽은 결과를 리턴한다. 즉 이 말은 우리는 input() 함수 자체가 파일의 readline()과 비슷하게 동작한다는 것인데, 쉘의 입출력 특성을 사용하여, input() 함수만으로 파일을 읽어들이는 것이 가능하다는 점 시사한다.

다만 차이가 있다면 파일 핸들러에서 readline()을 사용하면 개행 혹은 EOF를 만날 때까지 읽은 값을 리턴하는데, input() 함수는 EOF를 만나면 EOFError 예외를 일으킨다는 점이다.

따라서 우리는 입력된 문자열을 받아서 처리한 후 다시 결과 문자열을 되돌려주는 타입의 함수를 이용해서 표준입력(input)과 표준출력(print)을 연결하는 interact()라는 함수를 다음과 같이 작성할 수 있다.

def interact(fn):
  '''
  fn은 (str) -> str 타입의 함수이며
  input()으로 받아온 문자열을 fn을 통해 처리하고 그 결과를 print()로 출력한다.
  즉 프로세싱 함수를 받아서 표준입력과 표준출력 사이를 연결한다. 
  '''
  try:
    while True:
      print(fn(input()))
  except EOFError:
    pass

지난 시간에 각 줄의 숫자들의 합과 평균을 구하는 함수를 다시 생각해보자.

def sum_and_avg(ns):
  s = sum(ns)
  return s, s / len(ns)

## 각 줄을 처리하는 함수
def process(line):
  return '{0} {1:0.2f}'.format(*sum_and_avg([int(n) for n in line.split()]))

이제 최종 프로그램 실행 코드는 다음과 같이 완성된다.

if __name__ == '__main__':
  interact(process)

자, 이 프로그램을 실행하면 어떤 식으로 동작하는지 살펴보자.

  1. interact 함수가 process 함수를 인자로 받고 실행된다.
  2. input()이 호출되어 입력을 기다린다.
  3. 공백으로 구분된 일련의 정수값들을 입력하면 그 정수값들의 합과 평균(소수점 둘째자리까지)을 계산하여 출력한다.
  4. EOF가 입력되면 종료된다. (macOS에서는 ctrl+D, 윈도에서는 ctrl+Z) 그렇지 않으면 2번으로 돌아가서 이를 반복한다.

그런데 지난 시간에서도 많은 입력을 처리하기 위해서는 파일을 사용한다고 했다. 이 프로그램을 어떻게 만들 수 있을까? 바로 "리다이렉트(redirect)"를 이용하는 것이다. 쉘에서 실행되는 프로그램이 실행 중에 키보드로 입력을 받는다면, 이는 시스템의 표준입력을 이용하는 것이고, 터미널 상에서 기본적인 표준입력은 키보드에 해당한다.

하지만 다른 파일을 리다이렉트를 통해서 표준입력을 대체하도록 하면, 파일의 각 행을 한 번의 키보드 입력 (문자찍고 엔터누를때까지)으로 인식하게 된다.

따라서 여기서 만든 파일을 sumAgv.py라 저장하고 테스트해보도록 하자. 먼저 샘플 데이터를 생성하자.

import random

def make_ns(k=1):
  ns = [random.randrange(1, 100) for _ in range(k)]
  return ' '.join(str(x) for x in ns)

with open('data.txt', 'w') as f:
  data = '\n'.join(make_ns(8) for _ in range(100))
  f.writelines(data)

위 코드를 실행해서 100줄짜리 샘플데이터를 만든 후 쉘에서 다음과 같이 실행한다.

$ python sumAvg.py < data.txt

그러면 계산된 결과 100줄이 죽 표시될 것이다. 만약 그 결과를 다른 파일로 저장하고 싶다면? 표준 출력에 대해서도 리다이렉트를 수행한다.

$ python sumAvg.py < data.txt > result.txt

결과는 아무것도 출력되지 않는다. 대신에 현재 디렉토리에 result.txt라는 파일이 생성되어 있을 것이고, 이 파일을 열어보면 계산 결과가 들어있을 것이다.

이와같이 쉘의 표준입출력과 리다이렉트 개념을 이용하면 파일 액세스를 간단하게 input(), print()로 대체할 수 있다.

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함