반복 프로세스 기본

PythonPythonBeginner
지금 연습하기

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

💡 이 튜토리얼은 영어로 번역되었습니다. 원본을 보려면 영어로 전환

소개

이 섹션에서는 반복의 기본 프로세스를 살펴봅니다.

어디에나 있는 반복 (Iteration Everywhere)

다양한 객체가 반복을 지원합니다.

a = 'hello'
for c in a: ## a 의 문자들을 순회합니다 (Loop over characters in a)
    ...

b = { 'name': 'Dave', 'password':'foo'}
for k in b: ## 딕셔너리의 키들을 순회합니다 (Loop over keys in dictionary)
    ...

c = [1,2,3,4]
for i in c: ## 리스트/튜플의 항목들을 순회합니다 (Loop over items in a list/tuple)
    ...

f = open('foo.txt')
for x in f: ## 파일의 라인들을 순회합니다 (Loop over lines in a file)
    ...

반복: 프로토콜 (Iteration: Protocol)

for 문을 생각해 봅시다.

for x in obj:
    ## statements

내부적으로 무슨 일이 일어날까요?

_iter = obj.__iter__()        ## 이터레이터 객체 가져오기 (Get iterator object)
while True:
    try:
        x = _iter.__next__()  ## 다음 항목 가져오기 (Get next item)
        ## statements ...
    except StopIteration:     ## 더 이상 항목 없음 (No more items)
        break

for-loop와 함께 작동하는 모든 객체는 이 하위 수준의 반복 프로토콜을 구현합니다.

예시: 리스트 수동 반복.

>>> x = [1,2,3]
>>> it = x.__iter__()
>>> it
<listiterator object at 0x590b0>
>>> it.__next__()
1
>>> it.__next__()
2
>>> it.__next__()
3
>>> it.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in ? StopIteration
>>>

반복 지원 (Supporting Iteration)

반복에 대해 아는 것은 자신의 객체에 반복을 추가하려는 경우 유용합니다. 예를 들어, 사용자 정의 컨테이너를 만드는 경우입니다.

class Portfolio:
    def __init__(self):
        self.holdings = []

    def __iter__(self):
        return self.holdings.__iter__()
    ...

port = Portfolio()
for s in port:
    ...

연습 문제 6.1: 반복 시연 (Iteration Illustrated)

다음 리스트를 생성합니다.

a = [1,9,4,25,16]

이 리스트를 수동으로 반복합니다. __iter__()를 호출하여 이터레이터 (iterator) 를 얻고, __next__() 메서드를 호출하여 연속적인 요소를 얻습니다.

>>> i = a.__iter__()
>>> i
<listiterator object at 0x64c10>
>>> i.__next__()
1
>>> i.__next__()
9
>>> i.__next__()
4
>>> i.__next__()
25
>>> i.__next__()
16
>>> i.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

next() 내장 함수는 이터레이터의 __next__() 메서드를 호출하는 단축키입니다. 파일을 대상으로 사용해 보세요.

>>> f = open('portfolio.csv')
>>> f.__iter__()    ## 참고: 이것은 파일 자체를 반환합니다 (Note: This returns the file itself)
<_io.TextIOWrapper name='portfolio.csv' mode='r' encoding='UTF-8'>
>>> next(f)
'name,shares,price\n'
>>> next(f)
'"AA",100,32.20\n'
>>> next(f)
'"IBM",50,91.10\n'
>>>

파일의 끝에 도달할 때까지 next(f)를 계속 호출합니다. 어떤 일이 일어나는지 확인하세요.

연습 문제 6.2: 반복 지원 (Supporting Iteration)

경우에 따라, 특히 객체가 기존 리스트 또는 다른 반복 가능한 객체를 감싸는 경우, 자신의 객체 중 하나가 반복을 지원하도록 만들고 싶을 수 있습니다. 새로운 파일 portfolio.py에서 다음 클래스를 정의합니다.

## portfolio.py

class Portfolio:

    def __init__(self, holdings):
        self._holdings = holdings

    @property
    def total_cost(self):
        return sum([s.cost for s in self._holdings])

    def tabulate_shares(self):
        from collections import Counter
        total_shares = Counter()
        for s in self._holdings:
            total_shares[s.name] += s.shares
        return total_shares

이 클래스는 total_cost 속성과 같은 몇 가지 추가 메서드를 사용하여 리스트를 감싸도록 설계되었습니다. report.py에서 read_portfolio() 함수를 수정하여 다음과 같이 Portfolio 인스턴스를 생성하도록 합니다.

## report.py
...

import fileparse
from stock import Stock
from portfolio import Portfolio

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    with open(filename) as file:
        portdicts = fileparse.parse_csv(file,
                                        select=['name','shares','price'],
                                        types=[str,int,float])

    portfolio = [ Stock(d['name'], d['shares'], d['price']) for d in portdicts ]
    return Portfolio(portfolio)
...

report.py 프로그램을 실행해 보세요. Portfolio 인스턴스가 반복 가능하지 않기 때문에 심각하게 실패하는 것을 발견할 것입니다.

>>> import report
>>> report.portfolio_report('portfolio.csv', 'prices.csv')
... crashes ...

Portfolio 클래스를 수정하여 반복을 지원하도록 하여 이 문제를 해결합니다.

class Portfolio:

    def __init__(self, holdings):
        self._holdings = holdings

    def __iter__(self):
        return self._holdings.__iter__()

    @property
    def total_cost(self):
        return sum([s.shares*s.price for s in self._holdings])

    def tabulate_shares(self):
        from collections import Counter
        total_shares = Counter()
        for s in self._holdings:
            total_shares[s.name] += s.shares
        return total_shares

이 변경을 수행한 후, report.py 프로그램이 다시 작동해야 합니다. 이와 함께, 새로운 Portfolio 객체를 사용하도록 pcost.py 프로그램을 수정합니다. 다음과 같이 합니다.

## pcost.py

import report

def portfolio_cost(filename):
    '''
    Computes the total cost (shares*price) of a portfolio file
    '''
    portfolio = report.read_portfolio(filename)
    return portfolio.total_cost
...

작동하는지 테스트합니다.

>>> import pcost
>>> pcost.portfolio_cost('portfolio.csv')
44671.15
>>>

연습 문제 6.3: 더 적절한 컨테이너 만들기 (Making a more proper container)

컨테이너 클래스를 만들 때, 단순히 반복하는 것 이상을 수행하고 싶을 때가 많습니다. Portfolio 클래스를 수정하여 다음과 같은 다른 특수 메서드를 갖도록 합니다.

class Portfolio:
    def __init__(self, holdings):
        self._holdings = holdings

    def __iter__(self):
        return self._holdings.__iter__()

    def __len__(self):
        return len(self._holdings)

    def __getitem__(self, index):
        return self._holdings[index]

    def __contains__(self, name):
        return any([s.name == name for s in self._holdings])

    @property
    def total_cost(self):
        return sum([s.shares*s.price for s in self._holdings])

    def tabulate_shares(self):
        from collections import Counter
        total_shares = Counter()
        for s in self._holdings:
            total_shares[s.name] += s.shares
        return total_shares

이제 이 새로운 클래스를 사용하여 몇 가지 실험을 해보세요.

>>> import report
>>> portfolio = report.read_portfolio('portfolio.csv')
>>> len(portfolio)
7
>>> portfolio[0]
Stock('AA', 100, 32.2)
>>> portfolio[1]
Stock('IBM', 50, 91.1)
>>> portfolio[0:3]
[Stock('AA', 100, 32.2), Stock('IBM', 50, 91.1), Stock('CAT', 150, 83.44)]
>>> 'IBM' in portfolio
True
>>> 'AAPL' in portfolio
False
>>>

이에 대한 한 가지 중요한 관찰은, 일반적으로 코드는 Python 의 다른 부분이 일반적으로 작동하는 방식의 일반적인 어휘를 말하는 경우 "Pythonic"으로 간주된다는 것입니다. 컨테이너 객체의 경우, 반복, 인덱싱, 포함 및 기타 종류의 연산자를 지원하는 것이 이의 중요한 부분입니다.

요약

축하합니다! 반복 프로토콜 (Iteration Protocol) 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.

OSZAR »