Python 스크립트 작성 연습

Intermediate

This tutorial is from open-source community. Access the source code

소개

이 부분에서는 Python 스크립트 작성 실습에 대해 자세히 살펴보겠습니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 중급 레벨의 실험이며 완료율은 56%입니다.학습자들로부터 100%의 긍정적인 리뷰율을 받았습니다.

스크립트란 무엇인가?

*스크립트 (script)*는 일련의 문을 실행하고 중단하는 프로그램입니다.

## program.py

statement1
statement2
statement3
...

지금까지 우리는 주로 스크립트를 작성해 왔습니다.

문제점

유용한 스크립트를 작성하면 기능과 기능성이 증가할 것입니다. 다른 관련 문제에 적용하고 싶을 수도 있습니다. 시간이 지남에 따라 중요한 애플리케이션이 될 수 있습니다. 그리고 주의하지 않으면 거대하고 얽힌 혼란으로 변할 수 있습니다. 그러니 정리해 봅시다.

정의하기

이름은 나중에 사용되기 전에 항상 정의되어야 합니다.

def square(x):
    return x*x

a = 42
b = a + 2     ## Requires that `a` is defined

z = square(b) ## Requires `square` and `b` to be defined

순서가 중요합니다. 변수와 함수의 정의는 거의 항상 맨 위에 둡니다.

함수 정의하기

단일 *작업 (task)*과 관련된 모든 코드를 한 곳에 두는 것이 좋습니다. 함수를 사용하십시오.

def read_prices(filename):
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

함수는 반복적인 작업도 단순화합니다.

oldprices = read_prices('oldprices.csv')
newprices = read_prices('newprices.csv')

함수란 무엇인가?

함수는 이름이 지정된 일련의 구문 (statement) 입니다.

def funcname(args):
  statement
  statement
  ...
  return result

어떤 Python 구문이든 내부에 사용할 수 있습니다.

def foo():
    import math
    print(math.sqrt(2))
    help(math)

Python 에는 특별한 구문이 없습니다 (그래서 기억하기 쉽습니다).

함수 정의

함수는 어떤 순서로든 *정의 (define)*될 수 있습니다.

def foo(x):
    bar(x)

def bar(x):
    statements

## OR
def bar(x):
    statements

def foo(x):
    bar(x)

함수는 프로그램 실행 중에 실제로 사용 (use) (또는 호출 (call)) 되기 전에 정의되어야 합니다.

foo(3)        ## foo must be defined already

스타일적으로, 함수가 하향식 (bottom-up) 방식으로 정의되는 것을 더 흔하게 볼 수 있습니다.

하향식 스타일

함수는 구성 요소 (building block) 로 취급됩니다. 더 작고/단순한 블록이 먼저 옵니다.

## myprogram.py
def foo(x):
    ...

def bar(x):
    ...
    foo(x)          ## Defined above
    ...

def spam(x):
    ...
    bar(x)          ## Defined above
    ...

spam(42)            ## Code that uses the functions appears at the end

나중에 정의된 함수는 이전에 정의된 함수를 기반으로 합니다. 다시 말하지만, 이것은 단지 스타일의 문제입니다. 위의 프로그램에서 중요한 유일한 것은 spam(42)에 대한 호출이 마지막에 나타나는 것입니다.

함수 설계

이상적으로, 함수는 *블랙 박스 (black box)*여야 합니다. 함수는 전달된 입력값에 대해서만 작동해야 하며, 전역 변수와 알 수 없는 부작용을 피해야 합니다. 주요 목표는 *모듈성 (Modularity)*과 *예측 가능성 (Predictability)*입니다.

Doc Strings (독스트링)

독스트링 (doc-string) 형태로 문서를 포함하는 것은 좋은 습관입니다. 독스트링은 함수 이름 바로 뒤에 작성되는 문자열입니다. 이는 help() 함수, IDE 및 기타 도구에 정보를 제공합니다.

def read_prices(filename):
    '''
    Read prices from a CSV file of name,price data
    '''
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

독스트링에 대한 좋은 습관은 함수가 수행하는 작업에 대한 짧은 한 문장 요약을 작성하는 것입니다. 더 많은 정보가 필요한 경우, 인수에 대한 자세한 설명과 함께 사용법에 대한 간단한 예시를 포함합니다.

타입 어노테이션 (Type Annotations)

함수 정의에 선택적인 타입 힌트 (type hint) 를 추가할 수도 있습니다.

def read_prices(filename: str) -> dict:
    '''
    Read prices from a CSV file of name,price data
    '''
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

이 힌트는 작동상 아무런 영향을 미치지 않습니다. 이는 순전히 정보 제공을 위한 것입니다. 하지만 IDE, 코드 검사기 및 기타 도구에서 더 많은 작업을 수행하는 데 사용될 수 있습니다.

2 절에서, 주식 포트폴리오의 성과를 보여주는 보고서를 출력하는 report.py라는 프로그램을 작성했습니다. 이 프로그램은 몇 가지 함수로 구성되었습니다. 예를 들어:

## report.py
import csv

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    portfolio = []
    with open(filename) as f:
        rows = csv.reader(f)
        headers = next(rows)

        for row in rows:
            record = dict(zip(headers, row))
            stock = {
                'name' : record['name'],
                'shares' : int(record['shares']),
                'price' : float(record['price'])
            }
            portfolio.append(stock)
    return portfolio
...

하지만, 프로그램의 일부는 일련의 스크립트된 계산을 수행했습니다. 이 코드는 프로그램의 끝 부분 근처에 나타났습니다. 예를 들어:

...

## Output the report

headers = ('Name', 'Shares', 'Price', 'Change')
print('%10s %10s %10s %10s'  % headers)
print(('-' * 10 + ' ') * len(headers))
for row in report:
    print('%10s %10d %10.2f %10.2f' % row)
...

이 연습에서는 이 프로그램을 가져와서 함수 사용을 중심으로 조금 더 강력하게 구성할 것입니다.

연습 문제 3.1: 프로그램을 함수의 모음으로 구조화하기

report.py 프로그램을 수정하여 계산 및 출력을 포함한 모든 주요 작업이 함수의 모음에 의해 수행되도록 합니다. 구체적으로:

  • 보고서를 출력하는 함수 print_report(report)를 만듭니다.
  • 프로그램의 마지막 부분을 일련의 함수 호출로만 구성하고 다른 계산은 수행하지 않도록 변경합니다.

연습 문제 3.2: 프로그램 실행을 위한 최상위 함수 생성

프로그램의 마지막 부분을 가져와 단일 함수 portfolio_report(portfolio_filename, prices_filename)로 패키징합니다. 다음 함수 호출이 이전과 같이 보고서를 생성하도록 함수를 작동시킵니다.

portfolio_report('/home/labex/project/portfolio.csv', '/home/labex/project/prices.csv')

이 최종 버전에서 프로그램은 일련의 함수 정의와 맨 마지막에 portfolio_report()에 대한 단일 함수 호출 (프로그램에 관련된 모든 단계를 실행) 로 구성됩니다.

프로그램을 단일 함수로 변환하면 다른 입력에 대해 쉽게 실행할 수 있습니다. 예를 들어, 프로그램을 실행한 후 다음 문을 대화형으로 시도해 보십시오.

>>> portfolio_report('/home/labex/project/portfolio2.csv', '/home/labex/project/prices.csv')
... look at the output ...
>>> files = ['/home/labex/project/portfolio.csv', '/home/labex/project/portfolio2.csv']
>>> for name in files:
        print(f'{name:-^43s}')
        portfolio_report(name, '/home/labex/project/prices.csv')
        print()

... look at the output ...
>>>

해설

Python 은 일련의 문이 있는 파일만 있는 비교적 구조화되지 않은 스크립팅 코드를 작성하기 매우 쉽게 만들어줍니다. 큰 그림에서 가능한 한 함수를 활용하는 것이 거의 항상 더 좋습니다. 어느 시점에서 해당 스크립트가 커질 것이고, 조금 더 조직화되어 있기를 바라게 될 것입니다. 또한, 잘 알려지지 않은 사실은 Python 이 함수를 사용하면 약간 더 빠르게 실행된다는 것입니다.

요약

축하합니다! 스크립팅 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 기술을 향상시킬 수 있습니다.