ななぶろ

-お役立ち情報を気楽に紹介するブログ-

Pythonプログラム練習問題10選とPEP8コーディング規約徹底解説:初心者から中級者までステップアップ!

www.amazon.co.jp

Python プログラム練習問題 10 選と PEP8 コーディング規約徹底解説:初心者から中級者までステップアップ!

Python は、そのシンプルさと汎用性から、初心者からプロのエンジニアまで幅広い層に利用されている人気のプログラミング言語です。しかし、コードを書く上で重要なのは、機能だけでなく可読性と保守性も考慮することです。そこで登場するのが PEP8 というコーディング規約です。

この記事では、Python の基礎を習得したばかりの方から、より洗練されたコードを目指す中級者まで役立つように、PEP8 に準拠した Python プログラムの練習問題 10 選と、その詳細な解説を提供します。各問題には、解答例だけでなく、なぜ PEP8 に沿った書き方をするべきなのか、具体的なメリットについても説明します。

1. なぜ PEP8 が重要なのか?

PEP8 は、Python のコードを書く際のスタイルガイドラインです。これは、Python コミュニティによって合意されたものであり、一貫性のあるコードを記述するためのものです。

PEP8 に準拠するメリット:

  • 可読性の向上: 誰でも同じように書かれたコードを読むことができるため、理解しやすくなります。
  • 保守性の向上: コードの変更や修正が容易になり、バグの発見と修正も効率的に行えます。
  • チーム開発の円滑化: 複数の人が共同で開発する場合、コーディングスタイルが統一されていることで、コミュニケーションコストを削減できます。
  • Pythonic なコード: Python の特性を生かした、より自然で美しいコードを書くことができます。

PEP8 は単なる推奨事項ではなく、多くの企業やプロジェクトで採用されており、Python 開発者にとって必須の知識と言えるでしょう。

Why PEP8 Matters? (English Explanation)

PEP8 is a style guide for writing Python code. It's an agreed-upon standard within the Python community to ensure consistent coding practices. Adhering to PEP8 offers several benefits: improved readability, easier maintenance, smoother team collaboration, and more "Pythonic" code that leverages the language's strengths effectively. It’s not just a suggestion; it's widely adopted in industry projects and is essential knowledge for Python developers.

2. PEP8 の主要なルール (一部抜粋)

PEP8 には様々なルールがありますが、特に重要なものをいくつか紹介します。

  • インデント: スペース 4 つを使用する。タブではなくスペースを使うことが推奨されます。
  • 行の長さ: 最大 79 文字に抑える(ドキュメンテーション文字列やコメントでは 72 文字)。
  • 空白: 演算子、コンマ、コロンの前後に空白を入れる。関数呼び出し時の引数のカンマの後には空白を入れない。
  • 命名規則: 変数名、関数名は小文字で単語をアンダースコアで区切る (snake_case)。クラス名はキャメルケース (CamelCase) を使用する。定数はすべて大文字にする。
  • コメント: コードの意図や処理内容を明確に記述する。
  • ドキュメンテーション文字列 (Docstring): 関数、クラス、モジュールの冒頭に説明文を書く。

詳細なルールは、公式の PEP8 ドキュメントを参照してください: https://peps.python.org/pep-0008/

Key Rules of PEP8 (English Explanation)

PEP8 encompasses various rules, but here are some crucial ones:

  • Indentation: Use 4 spaces for indentation. Avoid tabs; spaces are preferred.
  • Line Length: Limit lines to a maximum of 79 characters (72 characters for docstrings and comments).
  • Whitespace: Add whitespace around operators, commas, and colons. Don't add whitespace after the comma in function calls.
  • Naming Conventions: Use snake_case for variable and function names (lowercase with underscores separating words). Use CamelCase for class names. Use all uppercase letters for constants.
  • Comments: Write clear comments explaining the purpose and logic of your code.
  • Docstrings: Include descriptive docstrings at the beginning of functions, classes, and modules.

Refer to the official PEP8 documentation for a complete list: https://peps.python.org/pep-0008/

3. Python プログラム練習問題 10 選 (PEP8 準拠)

それでは、実際に PEP8 に準拠した Python プログラムの練習問題を 10 問取り組んでみましょう。各問題には、難易度、解答例、解説が含まれています。

問題 1: FizzBuzz (初級)

  • 難易度: 初級
  • 内容: 1 から N までの整数を順番に出力するプログラムを作成してください。ただし、3 の倍数の場合は "Fizz"、5 の倍数の場合は "Buzz"、両方の倍数の場合は "FizzBuzz" と出力してください。
  • 解答例:
def fizzbuzz(n):
    """1 から n までの整数を出力する FizzBuzz ゲーム."""
    for i in range(1, n + 1):
        if i % 3 == 0 and i % 5 == 0:
            print("FizzBuzz")
        elif i % 3 == 0:
            print("Fizz")
        elif i % 5 == 0:
            print("Buzz")
        else:
            print(i)

# 例:n = 15 の場合
fizzbuzz(15)
  • 解説: def キーワードで関数を定義し、Docstring で関数の説明を記述しています。変数名には snake_case を使用し、インデントはスペース 4 つを使用しています。if, elif, else の各ブロックのインデントも一貫性を持たせています。

FizzBuzz (Beginner) (English Explanation)

  • Difficulty: Beginner
  • Description: Create a program that prints numbers from 1 to N sequentially. If the number is divisible by 3, print "Fizz"; if it's divisible by 5, print "Buzz"; and if it's divisible by both, print "FizzBuzz."
  • Solution:
def fizzbuzz(n):
    """Prints numbers from 1 to n, applying FizzBuzz rules."""
    for i in range(1, n + 1):
        if i % 3 == 0 and i % 5 == 0:
            print("FizzBuzz")
        elif i % 3 == 0:
            print("Fizz")
        elif i % 5 == 0:
            print("Buzz")
        else:
            print(i)

# Example: n = 15
fizzbuzz(15)
  • Explanation: The code defines a function fizzbuzz with a docstring explaining its purpose. It uses snake_case for variable names and consistent indentation (4 spaces). The conditional statements (if, elif, else) are properly indented to ensure readability.

問題 2: 素数判定 (初級)

  • 難易度: 初級
  • 内容: 与えられた整数が素数かどうかを判定する関数を作成してください。
  • 解答例:
def is_prime(n):
    """与えられた整数 n が素数かどうかを判定する."""
    if n <= 1:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

# 例:n = 7 の場合
print(is_prime(7))  # True
  • 解説: int(n ** 0.5) + 1 で平方根までしか計算しないことで、効率を向上させています。また、Docstring を使用して関数の説明を記述しています。

Prime Number Check (Beginner) (English Explanation)

  • Difficulty: Beginner
  • Description: Create a function that determines whether a given integer is prime.
  • Solution:
def is_prime(n):
    """Checks if a given integer n is a prime number."""
    if n <= 1:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

# Example: n = 7
print(is_prime(7))  # True
  • Explanation: The code defines a function is_prime with a docstring. It optimizes the prime check by only iterating up to the square root of n. Snake case is used for variable names, and indentation is consistent.

問題 3: リストの合計 (中級)

  • 難易度: 中級
  • 内容: 与えられたリスト内の数値の合計を計算する関数を作成してください。
  • 解答例:
def sum_list(numbers):
    """与えられた数値のリストの合計を計算する."""
    total = 0
    for number in numbers:
        total += number
    return total

# 例:numbers = [1, 2, 3, 4, 5] の場合
print(sum_list([1, 2, 3, 4, 5]))  # 15
  • 解説: for ループを使用してリストの要素を一つずつ処理し、合計を計算しています。変数名には snake_case を使用しています。

Sum of a List (Intermediate) (English Explanation)

  • Difficulty: Intermediate
  • Description: Create a function that calculates the sum of numbers in a given list.
  • Solution:
def sum_list(numbers):
    """Calculates the sum of numbers in a given list."""
    total = 0
    for number in numbers:
        total += number
    return total

# Example: numbers = [1, 2, 3, 4, 5]
print(sum_list([1, 2, 3, 4, 5]))  # 15
  • Explanation: The code defines a function sum_list with a docstring. It uses a for loop to iterate through the list and calculate the sum. Snake case is used for variable names.

問題 4: リスト内包表記 (中級)

  • 難易度: 中級
  • 内容: リスト内包表記を使って、1 から N までの偶数のリストを作成してください。
  • 解答例:
def generate_even_numbers(n):
    """1 から n までの偶数のリストを生成する."""
    even_numbers = [i for i in range(2, n + 1) if i % 2 == 0]
    return even_numbers

# 例:n = 10 の場合
print(generate_even_numbers(10))  # [2, 4, 6, 8, 10]
  • 解説: リスト内包表記は、簡潔で読みやすいコードを書くのに役立ちます。if i % 2 == 0 で偶数のみを抽出しています。

List Comprehension (Intermediate) (English Explanation)

  • Difficulty: Intermediate
  • Description: Use list comprehension to create a list of even numbers from 1 to N.
  • Solution:
def generate_even_numbers(n):
    """Generates a list of even numbers from 1 to n."""
    even_numbers = [i for i in range(2, n + 1) if i % 2 == 0]
    return even_numbers

# Example: n = 10
print(generate_even_numbers(10))  # [2, 4, 6, 8, 10]
  • Explanation: The code defines a function generate_even_numbers with a docstring. It uses list comprehension to create the list of even numbers in a concise and readable way.

問題 5: ファイルの読み込み (中級)

  • 難易度: 中級
  • 内容: 指定されたファイルからすべての行を読み込み、リストとして返す関数を作成してください。
  • 解答例:
def read_file(filename):
    """指定されたファイルからすべての行を読み込み、リストとして返す."""
    try:
        with open(filename, 'r') as f:
            lines = f.readlines()
        return lines
    except FileNotFoundError:
        print(f"Error: File '{filename}' not found.")
        return None

# 例:'my_file.txt' というファイルが存在する場合
lines = read_file('my_file.txt')
if lines:
    print(lines)
  • 解説: with open() を使用することで、ファイルを自動的に閉じることができます。try-except ブロックでエラー処理を行っています。

File Reading (Intermediate) (English Explanation)

  • Difficulty: Intermediate
  • Description: Create a function that reads all lines from a specified file and returns them as a list.
  • Solution:
def read_file(filename):
    """Reads all lines from a specified file and returns them as a list."""
    try:
        with open(filename, 'r') as f:
            lines = f.readlines()
        return lines
    except FileNotFoundError:
        print(f"Error: File '{filename}' not found.")
        return None

# Example: Assuming 'my_file.txt' exists
lines = read_file('my_file.txt')
if lines:
    print(lines)
  • Explanation: The code defines a function read_file with a docstring. It uses the with open() statement to ensure that the file is automatically closed after reading. It also includes error handling using a try-except block to catch FileNotFoundError.

問題 6: クラスの定義 (上級)

  • 難易度: 上級
  • 内容: Rectangle クラスを定義してください。このクラスは widthheight の属性を持ち、面積を計算する area() メソッドと、周囲長を計算する perimeter() メソッドを持つようにします。
  • 解答例:
class Rectangle:
    """四角形を表すクラス."""

    def __init__(self, width, height):
        """幅と高さを初期化する."""
        self.width = width
        self.height = height

    def area(self):
        """面積を計算する."""
        return self.width * self.height

    def perimeter(self):
        """周囲長を計算する."""
        return 2 * (self.width + self.height)

# 例:
rect = Rectangle(5, 10)
print(f"Area: {rect.area()}")  # Area: 50
print(f"Perimeter: {rect.perimeter()}")  # Perimeter: 30
  • 解説: クラス名はキャメルケースを使用しています。__init__() メソッドはコンストラクタであり、オブジェクトの初期化を行います。Docstring を使用してクラスとメソッドの説明を記述しています。

Class Definition (Advanced) (English Explanation)

  • Difficulty: Advanced
  • Description: Define a Rectangle class with attributes for width and height, and methods to calculate area and perimeter.
  • Solution:
class Rectangle:
    """Represents a rectangle."""

    def __init__(self, width, height):
        """Initializes the width and height of the rectangle."""
        self.width = width
        self.height = height

    def area(self):
        """Calculates the area of the rectangle."""
        return self.width * self.height

    def perimeter(self):
        """Calculates the perimeter of the rectangle."""
        return 2 * (self.width + self.height)

# Example:
rect = Rectangle(5, 10)
print(f"Area: {rect.area()}")  # Area: 50
print(f"Perimeter: {rect.perimeter()}")  # Perimeter: 30
  • Explanation: The code defines a class Rectangle with a docstring explaining its purpose. The __init__() method is the constructor, initializing the width and height attributes. Snake case is used for variable names within the methods. Docstrings are included to describe both the class and each method.

問題 7: デコレータ (上級)

  • 難易度: 上級
  • 内容: 関数の実行時間を計測するデコレータを作成してください。
  • 解答例:
import time

def timer(func):
    """関数の実行時間を計測するデコレータ."""
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function '{func.__name__}' took {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timer
def my_function():
    """時間のかかる処理."""
    time.sleep(1)  # 1秒待機

my_function()
  • 解説: デコレータは、関数を引数として受け取り、別の関数を返すことで、元の関数の動作を変更することができます。wrapper 関数内で start_timeend_time を記録し、実行時間を計算しています。

Decorator (Advanced) (English Explanation)

  • Difficulty: Advanced
  • Description: Create a decorator that measures the execution time of a function.
  • Solution:
import time

def timer(func):
    """Decorator to measure the execution time of a function."""
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function '{func.__name__}' took {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timer
def my_function():
    """A function that takes some time to execute."""
    time.sleep(1)  # Wait for 1 second

my_function()
  • Explanation: The code defines a decorator timer. It uses the wrapper function to record start and end times, calculate execution time, and print the result. The @timer syntax applies the decorator to the my_function.

問題 8: ジェネレータ (上級)

  • 難易度: 上級
  • 内容: フィボナッチ数列を生成するジェネレータを作成してください。
  • 解答例:
def fibonacci_generator(n):
    """フィボナッチ数列を生成するジェネレータ."""
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

# 例:最初の 10 個のフィボナッチ数を表示
for num in fibonacci_generator(10):
    print(num)
  • 解説: ジェネレータは、イテレータを返す関数です。yield キーワードを使用することで、値を一つずつ生成することができます。メモリ効率が良いのが特徴です。

Generator (Advanced) (English Explanation)

  • Difficulty: Advanced
  • Description: Create a generator that produces the Fibonacci sequence.
  • Solution:
def fibonacci_generator(n):
    """Generator to produce the Fibonacci sequence."""
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

# Example: Print the first 10 Fibonacci numbers
for num in fibonacci_generator(10):
    print(num)
  • Explanation: The code defines a generator fibonacci_generator. It uses the yield keyword to produce values one at a time, making it memory-efficient for generating large sequences.

問題 9: 例外処理 (中級)

  • 難易度: 中級
  • 内容: 0 で除算する可能性のある関数を作成し、ZeroDivisionError を適切に処理してください。
  • 解答例:
def divide(x, y):
    """2 つの数値を割り算する."""
    try:
        result = x / y
        return result
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")
        return None

# 例:
print(divide(10, 2))  # 5.0
print(divide(10, 0))  # Error: Cannot divide by zero.  None
  • 解説: try-except ブロックを使用して、例外を捕捉し、適切な処理を行います。これにより、プログラムがクラッシュするのを防ぎ、ユーザーにエラーメッセージを表示することができます。

Exception Handling (Intermediate) (English Explanation)

  • Difficulty: Intermediate
  • Description: Create a function that divides two numbers and handles the potential ZeroDivisionError.
  • Solution:
def divide(x, y):
    """Divides two numbers."""
    try:
        result = x / y
        return result
    except ZeroDivisionError:
        print("Error: Cannot divide by zero.")
        return None

# Example:
print(divide(10, 2))  # 5.0
print(divide(10, 0))  # Error: Cannot divide by zero.  None
  • Explanation: The code uses a try-except block to catch the ZeroDivisionError. This prevents the program from crashing and allows for graceful error handling, such as printing an informative message to the user.

問題 10: モジュール化 (上級)

  • 難易度: 上級
  • 内容: 問題を解決する関数を別のファイルに定義し、それをインポートして使用してください。
  • 解答例:

    my_module.py:

def greet(name):
    """指定された名前に挨拶する."""
    return f"Hello, {name}!"
`main.py`:
import my_module

# 例:
message = my_module.greet("World")
print(message)  # Hello, World!
  • 解説: モジュール化することで、コードを整理し、再利用性を高めることができます。大規模なプロジェクトでは、モジュール化は不可欠です。

Modularity (Advanced) (English Explanation)

  • Difficulty: Advanced
  • Description: Define a function to solve a problem in a separate file and import it into another file for use.
  • Solution:

    my_module.py:

def greet(name):
    """Greets the given name."""
    return f"Hello, {name}!"
`main.py`:
import my_module

# Example:
message = my_module.greet("World")
print(message)  # Hello, World!
  • Explanation: Modularity involves organizing code into separate files (modules) to improve readability and reusability. This is especially important for large projects.

4. PEP8 コーディング規約を徹底するためのツール

PEP8 に準拠したコードを書くことは重要ですが、手動で確認するのは大変です。そこで役立つツールがいくつかあります。

これらのツールを導入することで、PEP8 準拠のコードをより簡単に作成することができます。

5. まとめと今後の学習

この記事では、Python の練習問題 10 選と PEP8 コーディング規約について詳しく解説しました。これらの問題を解き、PEP8 に準拠したコーディングを実践することで、Python プログラミングスキルは確実に向上するでしょう。

今後の学習:

  • より高度な Python の機能 (メタクラス、デコレータの応用など) を学ぶ
  • デザインパターンを習得し、より洗練されたコードを書けるようにする
  • テスト駆動開発 (TDD) を実践し、品質の高いコードを作成する
  • Pythonic なコードの書き方を研究し、より効率的で読みやすいコードを目指す

Python は奥深い言語であり、常に新しい技術や知識を学ぶことが重要です。頑張ってください!