Python에서 순홤문을 작성하는 방법: While 및 For

2022. 11. 18. 20:45프로그래밍

728x90

 

 

How to Write a Loop in Python: While and For | The Renegade Coder

As this series grows, I often find myself revisiting the fundamentals. For instance, today we'll be learning how to write a loop in Python. Luckily…

therenegadecoder.com

이 시리즈가 성장함에 따라 나는 종종 기본을 다시 생각하게 됩니다. 예를 들어, 오늘 우리는 파이썬에서 순환문을 작성하는 방법을 배울 것입니다. 다행히도 재귀에 대한 몇 가지 보너스 자료가 있습니다.

요컨대, 순환문을 작성하는 두 가지 핵심 방법, while 및 for가 있습니다. 전통적인 순환 방법을 원한다면 while 순환문를 선택하고 반면, 순회할 시퀀스 또는 이터러블이 있는 경우 for 순환문을 선택하십시오. 순환(예: 트리 순회)으로 인해 엉망이 되는 시나리오를 발견하면 재귀 문으로 되될하 가는 것은 두려워하지 말아야 합니다.

 

문제 설명

프로그래밍을 처음 시작할 때 종종 다양한 문법으로 공부를 하게 됩니다. 예를 들어, 인쇄 및 변수에 대해 배울 수 있습니다. 그런 다음 지식을 산술 및 부울 표현식으로 확장할 수 있었을 겁니다. 모든 것이 잘 이해되면 조건문에 대해 배울 수도 있었을 것 입니다.

 

시간이 지남에 따라 "하지만 반복적으로 무언가를 하고 싶다면?" 이라고 자신에게 물었을 텐데요. 운 좋게도 대부분의 명령형 프로그래밍 언어에는 루핑이라는 문법들이 존재하고 있습니다. 기본적으로 우리는 어떤 조건을 만족할 때까지 작업을 반복하게 됩니다.

 

물론 당신이 다른 프로그래밍 언어를 해 봤다면, 이미 루핑(또는 최소한 재귀)에 대해 모두 알고 있을 것입니다. 문제는 새로운 문법에 익숙해지는 것이겠죠. 다행히도 다음 섹션에서 살펴볼 여러 가지 솔루션들을 가지고 있습니다.

 

솔루션

이 섹션에서는 Python에서 순환문을 작성하는 세 가지 다른 방법을 살펴보겠습니다. 먼저 함수형 기법인 재귀를 살펴보겠습니다. 그런 다음, while과 for의 두 가지 반복 기법에 대해 알아보겠습니다.

 

재귀

Python의 다양한 순환문 문법들을 살펴보기 전에 개념으로써 재귀를 먼저 언급하는 것이 중요하다고 생각합니다. 결국, 우리는 실제로 루프가 전혀 필요하지 않습니다. 스스로를 참조하는 함수를 작성하지 않아도 됩니다:

def recurse():
    recurse()
 

이 예제에서 우리는 자신을 호출하는 recurse()라는 함수를 작성했습니다. 하지만 이 프로그램을 실행하면 오류가 발생합니다:

>>> recurse()
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    recurse()
  File "<pyshell#1>", line 2, in recurse
    recurse()
  File "<pyshell#1>", line 2, in recurse
    recurse()
  File "<pyshell#1>", line 2, in recurse
    recurse()
  [Previous line repeated 991 more times]
RecursionError: maximum recursion depth exceeded
 

그렇죠, 이는 이해가 됩니다. 결국, 함수가 자기 자신을 호출하고 자기 자신를 호출한 다음 자기 자신를 호출한 다음 자기 자신를 호출합니다. 맞아요, 머리가 어지럽네요.

 

다행히도 이 코드는 매우 쉽게 고칠 수 있습니다. 특정 조건(예: 입력이 0보다 큰 경우)에서만 함수를 호출하는 조건을 추가하면 되니까요:

def recurse(i):
    if i > 0:
        recurse(i - 1)
 

이제 이 함수를 어떤 숫자를 넣어 보면, 오류를 내지지 않을 것입니다:

>>> recurse(5)
 

하지만, 이 코드는 실제로 무엇을 하는 것일까요? 그럼, 뭔가를 인쇄해 봅시다:

def recurse(i):
    print(f'Input is {i}')
    if i > 0:
        recurse(i - 1)
 

여기에서 우리는 이 함수가 호출될 때마다 입력을 표시하기 위해 f-string(여기에 대해 자세히 알아보기)을 사용했습니다:

>>> recurse(5)
Input is 5
Input is 4
Input is 3
Input is 2
Input is 1
Input is 0
 

이제 감이 잡히네요! 우리는 5를 입력하면 6번 실행되는 함수를 만들 수 있었습니다. 상상할 수 있듯이 이 메커니즘을 사용하여 많은 흥미로운 작업을 수행할 수 있습니다. 재귀에 대해 더 알고 싶다면 그에 대한 모든 것을 기사로 작성했습니다.

While 순환 문

재귀를 제외하고 루프에 대해 이야기합시다. 파이썬에는 두 가지 주요 루핑 메커니즘이 있습니다: while과 for가 그것입니다. 일반적으로 while 순환문 코스는 더 간단하기 때문에 처음에 다룹니다. if 문에 익숙하다면 while 루프는 거의 동일하게 보입니다:

while condition:
    do_thing()
 

조건이 참이면 루프 본문은 if 문처럼 실행됩니다. 그러나 본문이 실행된 후 조건이 다시 확인됩니다. 조건이 여전히 참이면 루프 본문으로 다시 한 번 떨어 집니다.

 

당연히 재귀 예제와 유사하게 동작하는 루프를 작성할 수 있습니다. 우리가 해야 할 일은 카운터 변수를 만들고 각 반복에 대해 카운트다운하는 것입니다:

i = 5
while i >= 0:
    print(f'Input is {i}')
    i -= 1
 

이 예에서 우리는 i라는 변수를 만들고 값을 5로 지정합니다. 그런 다음 i가 0보다 크거나 같은지 확인하여 루프를 시작합니다. 그래서 " 입력은 5”이고 감소는 i 로 해서 프로세스가 반복됩니다. 물론, 이제 i는 5 대신 4입니다. 전체 시간, i는 -1이 될 때까지 감소하고 순환 조건은 실패하게 될 것입니다.

 

Python에서 while은 무한 루프를 구현하는 데 사용할 수 있습니다. 다시 말해서, 얼마나 많은 반복을 미리 할 지 모를 때 while 루프를 사용하십시오. 예를 들어, while 루프는 파일에서 읽거나 사용자의 입력을 요청하는 데 적합합니다. 다음 섹션에서는 한정 루프의 예를 살펴보겠습니다.

 

For 순환문

Java, C 및 Python과 같은 많은 명령형 언어에는 순환문을 작성하는 방법이 두 가지 이상 있습니다. 예를 들어, Java에는 내가 알고 있는 최소 4개의 다른 루프 구문이 있습니다(예: while, for, for each, do while). 파이썬은 일을 단순하게 유지하려고 하기 때문에 루프 구문의 수는 제한되어 있습니다. 내가 아는 한 for와 while 두 가지만 있습니다.

 

이제 Python의 for 루프는 다른 언어의 for 루프와 다릅니다. 인덱스를 추적할 공간을 제공하는 대신 다른 언어의 각 순환 보다 더 많이 작동합니다. 즉, 목록처럼 반복할 무언가가 필요합니다. 위의 while 루프를 다시 만들어 보겠습니다:

indices = [5, 4, 3, 2, 1, 0]
for i in indices:
    print(f'Input is {i}')
 

이 순환문이 작동하도록 하려면 반복할 목록을 만들어야 했습니다. 분명히 이것은 이전 솔루션만큼 편리하지 않습니다. 운 좋게도 Python에는 다음과 같은 종류의 iterable을 생성하는 방법이 있습니다:

for i in range(5, -1, -1):
    print(f'Input is {i}')
 

Here, we’ve created a loop which will count down from 5 to 0 just like all our other loops. To do that, we used the range() function which generates a list-like structure from the inputs provided. In this case, 5 represents the inclusive starting value, the first -1 represents the exclusive ending value, and the second -1 represents the step (i.e. how many values to skip and in what direction).

여기에서 다른 모든 순환과 마찬가지로 5에서 0까지 카운트다운하는 순환를 만들었습니다. 이를 위해 제공된 입력에서 목록과 유사한 구조를 생성하는 range() 함수를 사용했습니다. 이 경우 5는 포괄적인 시작 값, 첫 번째 -1은 제외된 끝 값, 두 번째 -1은 단계(즉, 건너뛸 값과 방향)를 나타냅니다.

 

일반적으로 for 루프는 목록, 문자열 또는 생성기와 같은 시퀀스를 반복하는 데 더 유용합니다. 즉, range()와 같은 특수 함수를 사용하지 않고는 다른 언어의 for 루프처럼 정확하게 작동하지 않습니다.

성능

이 시점에서 이 세 가지 구성의 성능을 비교하는 것이 이치에 맞는지 확신할 수 없지만 동일한 작업을 수행하는 세 가지 솔루션을 이미 작성했습니다. 다시 말해, 우리는 단지 비교를 구걸할 뿐입니다. 비교를 시작하기위해서 세 가지 솔루션을 모두 문자열에 저장해 보겠습니다:

setup = """
i = 5
def recurse(i):
    # Removed print for sanity
    if i > 0:
        recurse(i - 1)
"""
 
recursion = """
recurse(5)
"""
 
while_loop = """
while i >= 0:
    # Removed print for sanity
    i -= 1
"""
 
for_loop = """
for i in range(5, -1, -1):
    pass  # Removed print for sanity
"""
 

그런 다음 다음과 같이 테스트를 실행할 수 있습니다:

>>> import timeit
>>> min(timeit.repeat(setup=setup, stmt=recursion))
0.7848201999999986
>>> min(timeit.repeat(setup=setup, stmt=while_loop))
0.040824499999999375
>>> min(timeit.repeat(setup=setup, stmt=for_loop))
0.34835850000000335
 

내가 정말 흥미롭게 발견한 한 가지는 while 순환문의 성능이었습니다. 그제서야 내 테스트가 약간 부정확하다는 것을 깨달았습니다. 특히 i를 설정 위치에 배치했으므로 첫 번째 반복 후에 0이 되었을 것입니다. 다시 말해서, while 루프는 if 문이 미화되었습니다. 설정 문자열을 업데이트했을 때 결과는 다음과 같습니다:

>>> setup = """
def recurse(i):
    # Removed print for sanity
    if i > 0:
        recurse(i - 1)
"""
>>> while_loop = """
i = 5
while i >= 0:
    # Removed print for sanity
    i -= 1
"""
>>> min(timeit.repeat(setup=setup, stmt=while_loop))
0.3415355000000204
 

이제 for 루프와 거의 동일합니다. 이것은 의미가 있어보입니다만,

StackOverflow에 대한 몇 가지 성능 토론을 읽고 있었고 for 루프는 전반적으로 더 빨라야 합니다. 당연히 조사해야 했기 때문에 많은 수에 대해 두 솔루션을 모두 업데이트했습니다:

>>> for_loop = """
for i in range(100, -1, -1):
    pass  # Removed print for sanity
"""
>>> min(timeit.repeat(setup=setup, stmt=for_loop))
1.2956954000001133
>>> while_loop = """
i = 100
while i >= 0:
    # Removed print for sanity
    i -= 1
"""
>>> min(timeit.repeat(setup=setup, stmt=while_loop))
4.765163399999892
 

100번은 내가 기꺼이 기다릴 수 있는 전부였다는 것이 밝혀졌습니다. 그렇지 않으면 이 테스트가 하루 종일 걸릴 수 있습니다. 즉, 이렇게 작은 숫자에서도 성능에는 분명한 차이가 있었습니다. 그 이유에 대한 추가 설명은 위의 토론을 자유롭게 확인하십시오.

 

도전과제

이제 루프를 작성하는 방법을 알았으므로 흥미로운 것을 시도해 보겠습니다. 목록의 목록(행렬이라고도 함)이 있다고 가정해 보겠습니다:

my_matrix = [
    [3, 5, 2, 4],
    [5, 9, 4, 2],
    [1, 8, 4, 3]
]
 

그리고 각 행(내부 목록)의 합계를 구하고 모든 행의 평균을 결정하려고 합니다. 위의 예를 사용하여 다음 행 합계를 얻습니다:

my_matrix = [
    [3, 5, 2, 4],  # 14
    [5, 9, 4, 2],  # 20
    [1, 8, 4, 3]   # 16
]
 

그런 다음 총계의 평균을 구합니다:

(14 + 20 + 16) / 3  # 16.666666666666668
 

완료되면 결과를 사용자에게 보고합니다.

 

이것은 우리에게 매우 간단한 작업처럼 보이지만 컴퓨터가 이를 수행하도록 훈련하려면 어떻게 해야 할까요? 즉, 다양한 순환 구문을 사용하여 이를 수행하려면 어떻게 해야 할까요? (힌트: 두 개의 루프를 중첩하고 싶을 수도 있습니다)?

 

해결책을 찾으면 아래에 댓글로 남겨주세요. 당연히, 나는 시작하기 위해 내 자신의 솔루션을 던져보도록 하죠.

 

약간의 요약

이 모든 것을 배제하고 솔루션을 다시 한 번 살펴보겠습니다:

# Recursion
def recurse(i):
    print(f'Input is {i}')
    if i > 0:
        recurse(i - 1)
recurse(5)
 
# While loop
i = 5
while i >= 0:
    print(f'Input is {i}')
    i -= 1
 
# For loop
for i in range(5, -1, -1):
    print(f'Input is {i}')
 
 

이상.