トラック
/
Python
Python
/
演習
/
グイドの豪華なラザニア
グイドの豪華なラザニア

グイドの豪華なラザニア

学習演習

はじめに

Pythonは、動的かつ強い型付けを持つプログラミング言語です。ダックタイピングと漸進的型付けの両方を、型ヒントによって取り入れています。

Pythonはさまざまなプログラミング_スタイル_をサポートしていますが、内部的には**Pythonのすべてはオブジェクト**です。これには数値、文字列、配列、さらには関数も含まれます。

こうしたことの意味については、トラックを進むなかでさらに詳しく掘り下げていきます。

この最初の演習では、Python言語の4つの主要な機能を紹介します。

  1. 名前の代入(変数と定数)、
  2. 関数(defキーワードとreturnキーワード)、
  3. コメント、および
  4. ドキュメント文字列。

Note

一般的に、Pythonトラックのコンテンツ、テスト、アナライザーツールは、Pythonコードのスタイルに関してPEP 8とPEP 257に示されたスタイル規約に従っています。さらに、1文字の変数名や"_"という名前の変数を使わないことが(強く)推奨されています。

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.

説明

お気に入りのレシピ本から、最高のラザニアを作るためのコードを書いていきます。

タスクは5つあり、どれもラザニア作りに関係しています。


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. 準備時間(分)を計算しましょう

ラザニアに加えたいnumber_of_layersを引数として受け取り、それを用意するのにかかる分数を返す関数preparation_time_in_minutes()を定義しましょう。 1層あたりの準備に2分かかるとします。

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

4. 合計経過時間(準備+焼き)を分単位で計算しましょう

2つの引数を取る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

グイドの豪華なラザニアを始める準備はできましたか?

Exercismに登録すれば、17個のコンセプト146個の演習、そして本物の人間によるメンタリングとともに、Pythonを学んでマスターできます。すべて無料です。