본문 바로가기
Python

[TIL - 20221215 파이썬 controlflow 흐름제어문의 구성]

by 위시우 2022. 12. 16.

흐름제어문(controlflow)

  • 데이터 혹은 사용자가 설정한 조건에 따라 코드의 작동 및 프로그램이 제어 되도록 하는 구문
    • 판별문, 조건문 또는 분기라고 부름 if, elif, else
    • 반복문, 무한반복문 for, while
    • 예외처리 break, try, except, continue

if, elif, else

  • 코드의 무조건적인 실행이 아닌 사용자 조건의 맞을 경우에만 코드가 실행되는 구조
  • 같은 프로그램 내 다양한 경우의 수가 있을 경우 사용
  • 코드의 흐름을 나누는 분기

✍️Key Point

  • 순차 : 위-> 아래 방향으로 코드가 순서대로 실행된다.
  • 분기 : If + 조건식 혹은 명제 --> True / False 로 판별할 수 있는 문
if 조건식1 : # 만약 조건식이 True 라면
    실행코드1 # 코드 실행. if 조건이 만족했을 경우 실행되는 코드라고 생각해도 됨
elif 조건식2 : # 만약 if 조건식이 False, elif 조건이 True 라면 
    실행코드2 # 코드가 실행 
else # 만약 위의 모든 조건식이 False라면
    실행코드 3: #코드가 실행 

if 연습문제

# 코드의 실행 결과는 무엇이 출력될까요?

print(1) # v
if True:
    print(2) # v
    if False:
        print(3) # 미출력
        print(4) # 미출력
    elif True:
        print(5) # v
        if True:
            print(6) # v
            print(7) # v
            if False:
                print(8) # 미출력
            elif True:
                print(9) # v
    else:
        print(10) # 미출력
    if True:
        print(11) # 쭉 내려오다가 그냥 참이니 출력임 
    print(12) # v
print(13) # v
  • 대체 왜 if True: print(11) 은 출력된걸까요?

    if False: & elif True : &else : 하나의 분기점 / if True : 는 별개의 분기점이기 때문입니다.

for, break

  • 코드의 반복적 실행(iterate) 을 위한 구문

  • 반복실행해야 하는 범위(range)가 있을 때 사용합니다.

  • 데이터의 갯수 혹은 분석하고자 하는 데이터의 범위 내에서 반복작업을 할 때 사용합니다.

✍️Key point

  • 데이터분석가의 경우, 정해진 데이터의 범위가 있고 정해진 범위 내에서 작업을 해야 하는 경우가 많아 while 문보다 for 문을 많이 사용

  • range() 는 index slicing 의 컨셉과 유사

    range(0,5)

    순서의 관점: 1번째 부터, 5번째까지

    index 의 관점 : 0 <= x < 5 -> 총 5개

  • 순서와 index 가 헷갈린다면, 그냥 한번 쳐보자

for 문의 구조

  • 반복자 : 구간(범위)를 순환하며 정의되는 변수
  • 반복범위 : list순서가 존재하는 자료구조
  • 관례적으로 심플한 반복자는 _(반복자를 작업에 사용하지 않을경우) 혹은 영문자 i(iterator)를 사용한다
for iterator in range: # 반복범위로 전달한 자료구조 혹은 범위 안에서 순환하며 반복자가 정의되며
    반복실행코드 # 위의 for문 반복범위 횟수만큼 반복실행코드가 반복되어 실행된다.

혹은 range()명령어로 반복작업 횟수로 설정 가능

  • range()
  • range(횟수)
  • range(x,y,z) x 부터 y-1 까지, z 개씩 (step) 커지면서

for 에서 초보자들은 len() and range() 같이 쓰면서 C 언어처럼 depth를 몇 개 씩 가져가는 실수를 한다.

list 안에 있는 원소들을 간단하게 뽑아보자

list = [10,20,30,40,50]
for n in list:
    print(n)
  ...  
  10
  20
  30
  40
  50
list = [10,20,30,40,50] # list 에서 반복을 돌면서 하고 싶다. 
for n in range(len):
    print(data[n])
    ...

이런 건 사람들 눈을 피나게 한다....

인덱스를 쓰고 싶다면 차라리 enumerate 함수를 쓰자

list = [10,20,30,40,50]
for n, x in enumerate(list):
    print(n, x)
...
0 4
1 9
2 1

그냥 위에 처럼 깔끔하게 쓸 수 있다. Think Pythonic 하자

for 문 중첩

  • 내부 for문 반복이 끝나야 밖의 for 문에서 그 다음 range
  • break 는 전체 for 문의 반복 깨는 것이 아님
  • When the break statement executes, it exits the loop and moves on the next statements. The break statement only applies to the inner-most loop. If this loop is within another loop, it will not break the outer loop.
for i in range(3):
    print(f'{i} 외부 반복중입니다.')
    for j in range(5):
        print(f'{j} 내부 반복중입니다.')
        if j == 2:
            break

자료구조 순환하는 for 문의 활용(매우 중요)

✍️Key point

  • for + enumerate () 조합으로 결측값/ 이상치를 확인할 수 있음

  • for rowno, row in enumerate(rows, start=1) 처럼 start = 1 하면 index 아닌 순서의 관점으로 이해 가능

  • csv 형식의 칼럼명(header) + 데이터(row) 구분해서 딕셔너리 키 : 밸루의 결합으로 만들 수 있음

  • list comprehension : test_list = [i for i in range(10)]

Exercise 2.15: A practical enumerate() example

  • for + enumerate () 조합으로 결측값/ 이상치를 확인할 수 있음

Recall that the file Data/missing.csv contains data for a stock portfolio, but has some rows with missing data. Using enumerate(), modify your pcost.py program so that it prints a line number with the warning message when it encounters bad input.

>>> cost = portfolio_cost('Data/missing.csv')
Row 4: Couldn't convert: ['MSFT', '', '51.23']
Row 7: Couldn't convert: ['IBM', '', '70.44']
>>>

To do this, you’ll need to change a few parts of your code.

...
for rowno, row in enumerate(rows, start=1): # s
    try:
        ...
    except ValueError:
        print(f'Row {rowno}: Bad row: {row}')

Exercise 2.16: Using the zip() function

In the file Data/portfolio.csv, the first line contains column headers. In all previous code, we’ve been discarding them.

>>> f = open('Data/portfolio.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> headers
['name', 'shares', 'price']
>>>

However, what if you could use the headers for something useful? This is where the zip() function enters the picture. First try this to pair the file headers with a row of data:

>>> row = next(rows)
>>> row
['AA', '100', '32.20']
>>> list(zip(headers, row))
[ ('name', 'AA'), ('shares', '100'), ('price', '32.20') ]
>>>

Notice how zip() paired the column headers with the column values. We’ve used list() here to turn the result into a list so that you can see it. Normally, zip() creates an iterator that must be consumed by a for-loop.

This pairing is an intermediate step to building a dictionary. Now try this:

>>> record = dict(zip(headers, row))
>>> record
{'price': '32.20', 'name': 'AA', 'shares': '100'}
>>>

This transformation is one of the most useful tricks to know about when processing a lot of data files. For example, suppose you wanted to make the pcost.py program work with various input files, but without regard for the actual column number where the name, shares, and price appear.

Modify the portfolio_cost() function in pcost.py so that it looks like this:

# pcost.py

def portfolio_cost(filename):
    ...
        for rowno, row in enumerate(rows, start=1):
            record = dict(zip(headers, row))
            try:
                nshares = int(record['shares'])
                price = float(record['price'])
                total_cost += nshares * price
            # This catches errors in int() and float() conversions above
            except ValueError:
                print(f'Row {rowno}: Bad row: {row}')
        ...

Now, try your function on a completely different data file Data/portfoliodate.csv which looks like this:

name,date,time,shares,price
"AA","6/11/2007","9:50am",100,32.20
"IBM","5/13/2007","4:20pm",50,91.10
"CAT","9/23/2006","1:30pm",150,83.44
"MSFT","5/17/2007","10:30am",200,51.23
"GE","2/1/2006","10:45am",95,40.37
"MSFT","10/31/2006","12:05pm",50,65.10
"IBM","7/9/2006","3:15pm",100,70.44
>>> portfolio_cost('Data/portfoliodate.csv')
44671.15
>>>

list comprehension

Exercise 2.17: Inverting a dictionary

A dictionary maps keys to values. For example, a dictionary of stock prices.

>>> prices = {
        'GOOG' : 490.1,
        'AA' : 23.45,
        'IBM' : 91.1,
        'MSFT' : 34.23
    }
>>>

If you use the items() method, you can get (key,value) pairs:

>>> prices.items()
dict_items([('GOOG', 490.1), ('AA', 23.45), ('IBM', 91.1), ('MSFT', 34.23)])
>>>

However, what if you wanted to get a list of (value, key) pairs instead? Hint: use zip().

>>> pricelist = list(zip(prices.values(),prices.keys()))
>>> pricelist
[(490.1, 'GOOG'), (23.45, 'AA'), (91.1, 'IBM'), (34.23, 'MSFT')]
>>>

Why would you do this? For one, it allows you to perform certain kinds of data processing on the dictionary data.

>>> min(pricelist)
(23.45, 'AA')
>>> max(pricelist)
(490.1, 'GOOG')
>>> sorted(pricelist)
[(23.45, 'AA'), (34.23, 'MSFT'), (91.1, 'IBM'), (490.1, 'GOOG')]
>>>

This also illustrates an important feature of tuples. When used in comparisons, tuples are compared element-by-element starting with the first item. Similar to how strings are compared character-by-character.

zip() is often used in situations like this where you need to pair up data from different places. For example, pairing up the column names with column values in order to make a dictionary of named values.

Note that zip() is not limited to pairs. For example, you can use it with any number of input lists:

>>> a = [1, 2, 3, 4]
>>> b = ['w', 'x', 'y', 'z']
>>> c = [0.2, 0.4, 0.6, 0.8]
>>> list(zip(a, b, c))
[(1, 'w', 0.2), (2, 'x', 0.4), (3, 'y', 0.6), (4, 'z', 0.8))]
>>>

Also, be aware that zip() stops once the shortest input sequence is exhausted.

>>> a = [1, 2, 3, 4, 5, 6]
>>> b = ['x', 'y', 'z']
>>> list(zip(a,b))
[(1, 'x'), (2, 'y'), (3, 'z')]
>>>
# 연습문제 
# 입력 값을 받는다. 
# 입금, 출금 선택시 입력값을 받는다. 

# 입금. 출금 시 balance를 변화시킨다. 
# 종료 4 을 받을때까지 계속 입력값을 받는다. 
mgs = '''
안녕하세요  MGS 은행입니다. 
원하시는 서비스 메뉴를 입력 해주세요. 

1. 입금
2. 출금
3. 잔액확인
4. 종료

최근 자동화기기를 모방한 사기거래가 기승을 부리고 있습니다. 출금 요청시 꼭 확인을 해주세요. 
'''
print(mgs)
balance = 100 * 10000
while True:
    menu = int(input('원하시는 서비스 메뉴를 입력 해주세요'))

    if menu == 1:
        print('입금 메뉴입니다.')
        deposit = int(input('입금하실 금액을 입력해주세요'))
        balance += deposit
        menu == 3
        menu == 4
        end = (input ('은행업무를 종료하시겠습니까? Y / N')) 

    elif menu == 2:
        print('출금 메뉴입니다.')
        withdrawal = int(input('출금하실 금액을 입력해주세요'))
        if withdrawal <= balance:
            balance -= withdrawal
            print(f'현재 잔액은 {balance}원입니다.')
            time.sleep(1)

        else:
            print('잔액이 부족합니다.')
            withdrawal = int(input('출금하실 금액을 입력해주세요'))

    elif menu == 3:
        print('잔액 확인 메뉴입니다.')
        print(f'현재 잔액은 {balance}원입니다.')
        time.sleep(1)
        `menu == 4`
        end = (input ('은행업무를 종료하시겠습니까? Y / N')) 

    elif menu == 4: 
        end = (input ('은행업무를 종료하시겠습니까? Y / N'))
        if end == 'Y':
            print('은행업무를 종료합니다.')
            break
        elif end == 'N':
            print('메뉴로 돌아갑니다.')

            # 함수가 아님

댓글