Percursos
/
Python
Python
/
Exercícios
/
A lasanha maravilhosa do Guido
A lasanha maravilhosa do Guido

A lasanha maravilhosa do Guido

Exercício de aprendizagem

Introdução

O Python é uma linguagem de programação de tipagem dinâmica e forte. Recorre tanto ao duck typing como à tipagem gradual através de indicações de tipo.

Embora o Python suporte muitos estilos de programação diferentes, internamente tudo em Python é um objeto. Isto inclui números, strings, listas e até funções.

Vamos aprofundar o que tudo isto significa à medida que avançamos no percurso.

Este primeiro exercício apresenta quatro funcionalidades principais da linguagem Python:

  1. Atribuição de nomes (variáveis e constantes),
  2. Funções (a palavra-chave def e a palavra-chave return),
  3. Comentários, e
  4. Docstrings.

Note

Em geral, o conteúdo, os testes e as ferramentas de análise do percurso de Python seguem as convenções de estilo descritas na PEP 8 e na PEP 257 para o estilo de código Python, com a sugestão adicional (e forte) de que não existam nomes de variáveis com uma única letra nem variáveis chamadas "_".

No percurso de Python, as variáveis escrevem-se sempre em snake_case, e as constantes em SCREAMING_SNAKE_CASE.


Atribuição de nomes (variáveis e constantes)

Os programadores podem associar nomes (também chamados variáveis) a qualquer tipo de objeto utilizando o operador de atribuição =: <name> = <value>. Ao longo do seu tempo de vida, um nome pode ser reatribuído (ou reassociado) a valores diferentes (tipos de objeto diferentes).

>>> 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".

Constantes

As constantes são nomes que devem ser atribuídos apenas uma vez num programa. Devem ser definidas ao nível do módulo (ficheiro), e são normalmente visíveis a todas as funções e classes do programa. Utilizar SCREAMING_SNAKE_CASE sinaliza que o nome não deve ser reatribuído, nem o seu valor alterado.

Funções

A palavra-chave def inicia uma definição de função. Cada função pode ter zero ou mais parâmetros formais entre parênteses (), seguidos de dois pontos :. As instruções do corpo da função começam na linha seguinte a def e têm de estar indentadas num bloco.

# 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

As funções devolvem um valor ou objeto explicitamente através da palavra-chave 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

As funções que não têm uma expressão explícita a seguir a um return devolvem implicitamente o objeto None. Os detalhes de None serão abordados num exercício posterior. Para efeitos deste exercício e desta explicação, None é um marcador de posição que representa nada, ou 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

As funções que omitem return também devolvem implicitamente o objeto None. Isto significa que, se não usares return numa função, o Python devolve o objeto None por ti.

# 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

Chamar funções

As funções são chamadas ou invocadas utilizando o seu nome seguido de (). A notação de ponto (.) é utilizada para chamar funções definidas dentro de uma classe ou módulo.

>>> 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

Comentários

Os comentários em Python começam com um # que não faz parte de uma string e terminam no fim da linha. Ao contrário de muitas outras linguagens de programação, o Python não suporta marcas de comentário multilinha. Cada linha de um bloco de comentários tem de começar com o caráter #.

Docstrings

A primeira instrução do corpo de uma função pode ser, opcionalmente, uma docstring, que resume de forma concisa o propósito da função ou do objeto. As docstrings são declaradas com três aspas duplas (""") indentadas ao mesmo nível do bloco de código:


# 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

As docstrings são lidas por ferramentas de documentação automática como o Sphinx e são devolvidas ao chamar o atributo especial .__doc__ no nome da função, do método ou da classe. As convenções gerais das docstrings estão descritas na PEP257, mas os formatos exatos variam consoante o projeto e a equipa. Os exercícios de conceitos do Exercism tentam seguir o estilo Google para código sem indicações de tipo.

As docstrings também podem funcionar como testes unitários leves, o que será abordado num exercício posterior.

# 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.

Instruções

Vais escrever algum código para te ajudar a cozinhar uma lasanha fantástica do teu livro de receitas preferido.

Tens cinco tarefas, todas relacionadas com a preparação da tua receita.


Note

Já começámos a primeira definição de função por ti no ficheiro stub, mas vais ter de escrever as restantes definições de função por tua conta. Também vais ter de definir as constantes que forem precisas. Lê com atenção as linhas de comentário #TODO no ficheiro stub. Quando terminares uma tarefa, remove o comentário TODO.


1. Define o tempo de cozedura previsto em minutos como uma constante

Define a constante EXPECTED_BAKE_TIME que representa quantos minutos a lasanha deve cozer no forno. De acordo com o teu livro de receitas, a lasanha deve estar no forno durante 40 minutos:

>>> print(EXPECTED_BAKE_TIME)
40

2. Calcula o tempo de cozedura restante em minutos

Completa a função bake_time_remaining() que recebe como argumento os minutos que a lasanha já esteve no forno e devolve quantos minutos ainda falta cozer, com base na constante EXPECTED_BAKE_TIME.

>>> bake_time_remaining(30)
10

3. Calcula o tempo de preparação em minutos

Define a função preparation_time_in_minutes() que recebe como argumento o number_of_layers que queres adicionar à lasanha e devolve quantos minutos vais gastar a prepará-las. Assume que cada camada demora 2 minutos a preparar.

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

4. Calcula o tempo total decorrido (preparação + cozedura) em minutos

Define a função elapsed_time_in_minutes() que recebe dois parâmetros como argumentos:

  • number_of_layers (o número de camadas adicionadas à lasanha)
  • elapsed_bake_time (o número de minutos que a lasanha já esteve a cozer no forno).

Esta função deve devolver o total de minutos que já passaste na cozinha a cozinhar: o tempo de preparação a fazer as camadas mais o tempo que a lasanha já esteve a cozer no forno.

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

5. Atualiza a receita com notas

Volta a percorrer a receita e acrescenta "notas" sob a forma de docstrings das funções.

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).
    
    """
Editar via GitHub A ligação abre numa nova janela ou separador
Python Exercism

Estás pronto para começar A lasanha maravilhosa do Guido?

Inscreve-te no Exercism para aprenderes e dominares Python com 17 conceitos146 exercícios, e mentoria humana real, tudo grátis.