트랙
/
Python
Python
/
연습 문제
/
Guido의 멋진 라자냐
Guido의 멋진 라자냐

Guido의 멋진 라자냐

학습 연습 문제

소개

Python은 동적이면서 강한 타입을 가진 프로그래밍 언어예요. 덕 타이핑과 타입 힌트를 통한 점진적 타이핑을 모두 활용해요.

Python은 다양한 프로그래밍 _스타일_을 지원하지만, 내부적으로 Python의 모든 것은 객체예요. 숫자, 문자열, 배열, 심지어 함수까지도 모두 객체예요.

이 모든 것이 무슨 의미인지는 트랙을 진행하면서 더 자세히 살펴볼 거예요.

이 첫 번째 연습 문제에서는 Python의 네 가지 주요 언어 기능을 소개해요:

  1. 이름 할당(변수와 상수),
  2. 함수(def 키워드와 return 키워드),
  3. 주석,
  4. 독스트링.

Note

일반적으로 Python 트랙의 콘텐츠, 테스트, 분석 도구는 Python 코드 스타일에 대해 PEP 8과 PEP 257에 설명된 스타일 규칙을 따르며, 한 글자짜리 변수 이름이나 "_"라는 이름의 변수를 사용하지 않도록 (강하게) 권장해요.

Python 트랙에서는 변수를 항상 snake_case로 작성하고, 상수는 SCREAMING_SNAKE_CASE로 작성해요.


이름 할당(변수와 상수)

프로그래머는 할당 = 연산자를 사용해 이름(_변수_라고도 해요)을 모든 타입의 객체에 바인딩할 수 있어요: <name> = <value>. 이름은 생명 주기 동안 다른 값(다른 객체 타입)으로 다시 할당(또는 다시 바인딩)할 수 있어요.

>>> my_first_variable = 1  #<-- my_first_variable bound to an integer object of value one.
>>> my_first_variable = 2  #<-- my_first_variable re-assigned to integer value 2.

>>> print(type(my_first_variable))
<class 'int'>

>>> print(my_first_variable)
2

>>> my_first_variable = "Now, I'm a string." #<-- You may re-bind a name to a different object type and value.
>>> print(type(my_first_variable))
<class 'str'>

>>> my_first_variable = 'You can call me "str".' #<-- Strings can be declared using single or double quote marks.
>>> print(my_first_variable)
You can call me "str".

상수

상수는 프로그램에서 한 번만 할당하도록 의도된 이름이에요. 상수는 모듈(파일) 수준에서 정의해야 하며, 보통 프로그램의 모든 함수와 클래스에서 볼 수 있어요. SCREAMING_SNAKE_CASE를 사용하면 이 이름을 다시 할당하거나 값을 변경해서는 안 된다는 신호를 줘요.

함수

def 키워드는 함수 정의를 시작해요. 각 함수는 괄호 () 안에 0개 이상의 형식 매개변수를 가질 수 있고, 그 뒤에 콜론 :이 와요. 함수의 _본문_을 이루는 문은 def 다음 줄부터 시작하며 _들여쓰기된 블록_으로 작성해야 해요.

# The body of a function is indented by 2 spaces, & prints the sum of the numbers.
def add_two_numbers(number_one, number_two):
  total = number_one + number_two
  print(total)  

>>> add_two_numbers(3, 4)
7


# Inconsistent indentation in your code blocks will raise an error.
>>> def add_three_numbers_misformatted(number_one, number_two, number_three):
...     result = number_one + number_two + number_three   # This was indented by 4 spaces.
...    print(result)     #this was only indented by 3 spaces
...
...
  File "<stdin>", line 3
    print(result)
    ^
IndentationError: unindent does not match any outer indentation level

함수는 return 키워드를 통해 값이나 객체를 명시적으로 반환해요:

# Function definition on first line, explicit return used on final line.
>>> def add_two_numbers(number_one, number_two):
        return number_one + number_two   


# Calling the function in the Python shell returns the sum of the numbers.
>>> add_two_numbers(3, 4)
7

# Assigning the function call to a variable and printing it 
# will also return the value.
>>> sum_with_return = add_two_numbers(5, 6)
>>> print(sum_with_return)
11

return 뒤에 명시적인 표현식이 없는 함수는 None 객체를 암시적으로 반환해요. None의 세부 사항은 나중 연습 문제에서 다뤄요. 이 연습 문제와 설명을 위해, None은 아무것도, 즉 null을 나타내는 자리 표시자예요:


# This function will return `None`
def square_a_number(number):
    square = number * number
    return # <-- note that this return is not followed by an expression

# Calling the function in the Python shell appears 
# to not return anything at all.
>>> square_a_number(2)
>>>


# Using print() with the function call shows that 
# the function is actually returning the **None** object.
>>> print(square_a_number(2))
None

return을 생략한 함수도 None 객체를 암시적으로 반환해요. 즉, 함수에서 return을 사용하지 않으면 Python이 대신 None 객체를 반환해요.

# This function omits a return keyword altogether.
def add_two_numbers(number_one, number_two):
  result = number_one + number_two

>>> add_two_numbers(5, 7)
>>> print(add_two_numbers(5, 7))
None

# Assigning the function call to a variable and printing 
# the variable will also show None.
>>> sum_without_return = add_two_numbers(5, 6)
>>> print(sum_without_return)
None

함수 호출

함수는 이름 뒤에 ()를 붙여서 호출해요. 클래스나 모듈 안에 정의된 함수를 호출할 때는 점(.) 표기법을 사용해요.

>>> def raise_to_power(number, power):
...     return number ** power
...

>>> raise_to_power(3,3) # <--Invoking the function with the arguments 3 and 3.
27


# A mismatch between the number of parameters and the number of arguments will raise an error.
>>> raise_to_power(4,)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: raise_to_power() missing 1 required positional argument: 'power'


# Calling methods or functions in classes and modules.
>>> start_text = "my silly sentence for examples."
>>> str.upper(start_text)  # <--Calling the upper() method from the built-in str class on start_text.
'MY SILLY SENTENCE FOR EXAMPLES.'


# Importing the math module
>>> import math

>>> math.pow(2,4)  # <--Calling the pow() function from the math module.
16.0

주석

Python에서 주석은 문자열의 일부가 아닌 #으로 시작해서 줄 끝에서 끝나요. 다른 많은 프로그래밍 언어와 달리 Python은 여러 줄 주석 표시를 지원하지 않아요. 주석 블록의 각 줄은 # 문자로 시작해야 해요.

독스트링

함수 본문의 첫 번째 문은 선택적으로 독스트링이 될 수 있으며, 이는 함수나 객체의 목적을 간결하게 요약해요. 독스트링은 코드 블록과 같은 수준으로 들여쓰기된 삼중 큰따옴표(""")로 선언해요:


# An example from PEP257 of a multi-line docstring
# reformatted to use Google style non-type hinted docstrings.
# Some additional details can be found in the Sphinx documentation:
# https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html#getting-started

def complex(real=0.0, imag=0.0):
    """Form a complex number.

    Keyword Arguments:
        real (float): The real part of the number (default 0.0)
        imag (float): The imaginary part of the number (default 0.0)
        
    """

    if imag == 0.0 and real == 0.0:
        return complex_zero

독스트링은 Sphinx 같은 자동 문서화 도구가 읽으며, 함수, 메서드, 클래스 이름에 특수 속성 .__doc__을 호출하면 반환돼요. 일반적인 독스트링 규칙은 PEP257에 나와 있지만, 정확한 형식은 프로젝트와 팀마다 달라요. Exercism의 개념 연습 문제는 타입 힌트가 없는 코드에 Google 스타일을 따르려고 해요.

독스트링은 가벼운 단위 테스트로도 사용할 수 있으며, 이는 나중 연습 문제에서 다뤄요.

# An example on a user-defined function using a Google style docstring. 
>>> def raise_to_power(number, power):
    """Raise a number to an arbitrary power.

    Parameters:
        number (int): The base number.
        power (int): The power to raise the base number to.
    
    Returns:
        int: The number raised to the specified power.
    
    Takes a number and raises it to the specified power, returning the result.

    """

    return number ** power
...

# Calling the .__doc__ attribute of the function and printing the result.
>>> print(raise_to_power.__doc__)
Raise a number to an arbitrary power.

Parameters:
    number (int): The base number.
    power (int): The power to raise the base number to.

Returns:
    int: The number raised to the specified power.

Takes a number and raises it to the specified power, returning the result.

지침

좋아하는 요리책에 나오는 근사한 라자냐를 만들 수 있도록 도와주는 코드를 작성해 볼 거예요.

레시피를 만드는 것과 관련된 다섯 개의 과제가 있어요.


Note

스텁 파일에 첫 번째 함수 정의는 시작해 두었지만, 나머지 함수 정의는 직접 작성해야 해요. 상수도 직접 정의해야 해요. 스텁 파일의 #TODO 주석 줄을 잘 읽어 보세요. 과제를 끝내면 TODO 주석을 지워 주세요.


1. 예상 굽기 시간(분)을 상수로 정의하기

라자냐를 오븐에서 몇 분 동안 구워야 하는지를 나타내는 EXPECTED_BAKE_TIME 상수를 정의해요. 요리책에 따르면 라자냐는 오븐에서 40분 동안 구워야 해요:

>>> print(EXPECTED_BAKE_TIME)
40

2. 남은 굽기 시간(분) 계산하기

bake_time_remaining() 함수를 완성해요. 이 함수는 라자냐가 오븐에 있던 실제 시간(분)을 인자로 받아서, EXPECTED_BAKE_TIME 상수를 기준으로 라자냐가 앞으로 몇 분을 더 구워야 하는지 반환해요.

>>> bake_time_remaining(30)
10

3. 준비 시간(분) 계산하기

preparation_time_in_minutes() 함수를 정의해요. 이 함수는 라자냐에 추가하려는 number_of_layers를 인자로 받아서, 그것을 만드는 데 몇 분이 걸리는지 반환해요. 각 층을 준비하는 데 2분이 걸린다고 가정해요.

>>> def preparation_time_in_minutes(number_of_layers):
        ...
        ...
        
>>> preparation_time_in_minutes(2)
4

4. 총 소요 시간(분) 계산하기 (준비 + 굽기)

elapsed_time_in_minutes() 함수를 정의해요. 이 함수는 두 개의 매개변수를 인자로 받아요:

  • number_of_layers (라자냐에 추가한 층의 수)
  • elapsed_bake_time (라자냐가 지금까지 오븐에서 구운 시간(분)).

이 함수는 주방에서 요리한 총 시간(분)을 반환해야 해요. 즉, 층을 쌓는 준비 시간 + 라자냐가 오븐에서 구운 시간이에요.

>>> def elapsed_time_in_minutes(number_of_layers, elapsed_bake_time):
        ...
        ...
        
>>> elapsed_time_in_minutes(3, 20)
26

5. 레시피에 메모 추가하기

레시피를 다시 훑어보면서 함수 독스트링 형태의 "메모"를 추가해요.

def elapsed_time_in_minutes(number_of_layers, elapsed_bake_time):
    """Calculate the elapsed cooking time.
    
    Parameters:
        number_of_layers (int): The number of layers in the lasagna.
        elapsed_bake_time (int): Time the lasagna has been baking in the oven.
    
    Returns:
        int: The total time elapsed (in minutes) preparing and baking.

    This function takes two integers representing the number of lasagna 
    layers and the time already spent baking the lasagna. It calculates 
    the total elapsed minutes spent cooking (preparing + baking).
    
    """
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Python Exercism

Guido의 멋진 라자냐 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Python 트랙을 개념 17개연습 문제 146개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.