ななぶろ

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

Pythonプログラム練習問題10問:メソッドを活用しよう!

www.amazon.co.jp

Python プログラム練習問題 10 問:メソッドを活用しよう!

Python is a popular programming language used by everyone from beginners to professionals due to its simplicity and versatility. Object-oriented programming (OOP) features, in particular, are extremely important for improving code reusability and maintainability. This article focuses on the concept of "methods" in Python and introduces 10 practice problems to deepen your understanding.

メソッドとは何か?

What is a Method?

まず、「メソッド」とは何でしょうか? 簡単に言うと、メソッドはオブジェクトに関連付けられた関数です。 クラス (設計図) を定義する際に、そのクラスのインスタンス (具体的な実体) が持つべき振る舞いを記述するために使用されます。

First, what is a "method"? Simply put, a method is a function associated with an object. It's used when defining a class (blueprint) to describe the behavior that instances (concrete entities) of that class should have.

例として、犬というクラスを考えてみましょう。このクラスには、「吠える」「食べる」「走る」といった行動が考えられます。これらの行動はメソッドとして実装できます。

For example, let's consider a "Dog" class. This class might have behaviors like "barking," "eating," and "running." These behaviors can be implemented as methods.

class Dog:
    def __init__(self, name):
        """コンストラクタ:名前を設定する"""
        self.name = name

    def bark(self):
        """吠えるメソッド"""
        print("Woof!")

    def eat(self, food):
        """食べるメソッド。引数foodで食べ物を指定"""
        print(f"{self.name} is eating {food}.")

    def run(self, distance):
        """走るメソッド。引数distanceで距離を指定"""
        print(f"{self.name} ran {distance} meters.")

解説:

  • class Dog:: これは Dog という名前の新しいクラスを定義しています。
  • __init__(self, name):: これはコンストラクタと呼ばれる特別なメソッドです。オブジェクトが作成されるときに自動的に呼び出されます。self は、そのオブジェクト自身を参照する特殊な引数です。name は、犬の名前を設定するための引数です。
  • self.name = name: これは、オブジェクトの name 属性に渡された名前を格納します。
  • bark(self):, eat(self, food):, run(self, distance):: これらはそれぞれ、犬が吠えたり、食べたり、走ったりするメソッドです。 self 引数は必須であり、メソッドが呼び出されるオブジェクト自身を参照するために使用されます。eat メソッドは food という引数を受け取り、run メソッドは distance という引数を受け取ります。

Explanation:

  • class Dog:: This defines a new class named "Dog."
  • __init__(self, name):: This is a special method called the constructor. It's automatically called when an object is created. self is a special argument that refers to the object itself. name is an argument for setting the dog's name.
  • self.name = name: This stores the passed-in name in the object's name attribute.
  • bark(self):, eat(self, food):, run(self, distance):: These are methods that allow the dog to bark, eat, and run, respectively. The self argument is mandatory and used to refer to the object itself when the method is called. The eat method takes a food argument, and the run method takes a distance argument.

オブジェクトの作成とメソッドの呼び出し:

my_dog = Dog("Buddy")
my_dog.bark()       # 出力: Woof!
my_dog.eat("bone")  # 出力: Buddy is eating bone.
my_dog.run(100)     # 出力: Buddy ran 100 meters.

Creating an Object and Calling Methods:

my_dog = Dog("Buddy")
my_dog.bark()       # Output: Woof!
my_dog.eat("bone")  # Output: Buddy is eating bone.
my_dog.run(100)     # Output: Buddy ran 100 meters.

メソッドの基本的な使い方

Basic Usage of Methods

メソッドは、オブジェクトの状態を変更したり、オブジェクトに関する情報を返したりするために使用されます。 self 引数は、メソッドが呼び出されるオブジェクト自身を参照するために常に必要です。 メソッドは、クラス内で定義された関数と同様に、引数を受け取ったり、値を返したりすることができます。

Methods are used to modify the state of an object or return information about the object. The self argument is always required for methods, and it refers to the object itself when the method is called. Like functions defined within a class, methods can accept arguments and return values.

例:

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

Example:

class Rectangle:
    def __init__(self, width, height):
        """Constructor: Sets the width and height."""
        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)

rect = Rectangle(5, 10)
print(f"Area: {rect.area()}")       # Output: Area: 50
print(f"Perimeter: {rect.perimeter()}") # Output: Perimeter: 30

メソッドの練習問題:基礎編

Practice Problems: Basic Level

以下に、メソッドの基本的な使い方を理解するための練習問題をいくつか紹介します。

Here are some practice problems to help you understand the basic usage of methods.

問題 1: Circle クラスを作成し、半径 radius を属性として持ちます。 area() メソッドと circumference() メソッドを実装して、それぞれ円の面積と円周を計算するようにします。

Problem 1: Create a Circle class that has a radius as an attribute. Implement area() and circumference() methods to calculate the area and circumference of the circle, respectively.

import math

class Circle:
    def __init__(self, radius):
        """コンストラクタ:半径を設定する"""
        self.radius = radius

    def area(self):
        """面積を計算するメソッド"""
        return math.pi * self.radius**2

    def circumference(self):
        """円周を計算するメソッド"""
        return 2 * math.pi * self.radius

# 使用例
my_circle = Circle(5)
print(f"Area: {my_circle.area()}")       # 出力: Area: 78.53981633974483
print(f"Circumference: {my_circle.circumference()}") # Output: Circumference: 31.41592653589793

問題 2: Book クラスを作成し、タイトル title と著者 author を属性として持ちます。 display_info() メソッドを実装して、本の情報を表示するようにします。

Problem 2: Create a Book class that has a title as an attribute and an author as an attribute. Implement a display_info() method to display the book's information.

class Book:
    def __init__(self, title, author):
        """コンストラクタ:タイトルと著者を設定する"""
        self.title = title
        self.author = author

    def display_info(self):
        """本の情報を表示するメソッド"""
        print(f"Title: {self.title}")
        print(f"Author: {self.author}")

# 使用例
my_book = Book("The Lord of the Rings", "J.R.R. Tolkien")
my_book.display_info()

問題 3: TemperatureConverter クラスを作成し、温度 temperature を属性として持ちます。 摂氏から華氏への変換を行う celsius_to_fahrenheit() メソッドと、華氏から摂氏への変換を行う fahrenheit_to_celsius() メソッドを実装します。

Problem 3: Create a TemperatureConverter class that has a temperature as an attribute. Implement a celsius_to_fahrenheit() method to convert from Celsius to Fahrenheit and a fahrenheit_to_celsius() method to convert from Fahrenheit to Celsius.

class TemperatureConverter:
    def __init__(self, temperature):
        """コンストラクタ:温度を設定する"""
        self.temperature = temperature

    def celsius_to_fahrenheit(self):
        """摂氏から華氏への変換メソッド"""
        return (self.temperature * 9/5) + 32

    def fahrenheit_to_celsius(self):
        """華氏から摂氏への変換メソッド"""
        return (self.temperature - 32) * 5/9

# 使用例
temp = TemperatureConverter(25)  # 25 degrees Celsius
print(f"Fahrenheit: {temp.celsius_to_fahrenheit()}") # Output: Fahrenheit: 77.0

メソッドの練習問題:応用編

Practice Problems: Advanced Level

以下に、メソッドのより高度な使い方を理解するための練習問題をいくつか紹介します。

Here are some practice problems to help you understand more advanced usage of methods.

問題 4: BankAccount クラスを作成し、口座番号 account_number と残高 balance を属性として持ちます。 預金 (deposit) メソッドと引き出し (withdraw) メソッドを実装して、それぞれ残高に金額を追加したり減らしたりするようにします。 残高がマイナスになるような引き出しは許可しないようにしてください。

Problem 4: Create a BankAccount class that has an account number as an attribute and a balance as an attribute. Implement a deposit() method and a withdraw() method to add or subtract amounts from the balance, respectively. Do not allow withdrawals that would result in a negative balance.

class BankAccount:
    def __init__(self, account_number, initial_balance):
        """コンストラクタ:口座番号と初期残高を設定する"""
        self.account_number = account_number
        self.balance = initial_balance

    def deposit(self, amount):
        """預金メソッド"""
        if amount > 0:
            self.balance += amount
            print(f"Deposited {amount}. New balance: {self.balance}")
        else:
            print("Deposit amount must be positive.")

    def withdraw(self, amount):
        """引き出しメソッド"""
        if amount > 0 and self.balance >= amount:
            self.balance -= amount
            print(f"Withdrew {amount}. New balance: {self.balance}")
        elif amount <= 0:
            print("Withdrawal amount must be positive.")
        else:
            print("Insufficient funds.")

# 使用例
account = BankAccount("123456789", 1000)
account.deposit(500)  # Output: Deposited 500. New balance: 1500
account.withdraw(2000) # Output: Insufficient funds.

問題 5: Shape という抽象クラスを作成し、 area() メソッドを定義します。 このメソッドは、サブクラスでオーバーライドされることを想定しています。 Circle クラスと Rectangle クラスを Shape から継承させ、それぞれの area() メソッドを実装します。

Problem 5: Create an abstract class called Shape and define an area() method. This method is intended to be overridden in subclasses. Inherit Circle and Rectangle classes from Shape and implement their respective area() methods. (Note: Python doesn't have a built-in abstract base class mechanism like Java or C++. We can simulate it using inheritance and checking for the existence of the method.)

class Shape:
    def area(self):
        """面積を計算する抽象メソッド。サブクラスでオーバーライドされることを想定"""
        raise NotImplementedError("Subclasses must implement this method")

class Circle(Shape):
    def __init__(self, radius):
        """コンストラクタ:半径を設定する"""
        self.radius = radius

    def area(self):
        """面積を計算するメソッド"""
        return 3.14159 * self.radius**2  # Using a fixed value for pi

class Rectangle(Shape):
    def __init__(self, width, height):
        """コンストラクタ:幅と高さを設定する"""
        self.width = width
        self.height = height

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

# 使用例
circle = Circle(5)
rectangle = Rectangle(4, 6)

print(f"Circle Area: {circle.area()}")       # Output: Circle Area: 78.53975
print(f"Rectangle Area: {rectangle.area()}") # Output: Rectangle Area: 24

問題 6: Vehicle クラスを作成し、 start_engine() メソッドと stop_engine() メソッドを定義します。 Car クラスと Motorcycle クラスを Vehicle から継承させ、それぞれのメソッドをオーバーライドして、異なるエンジン始動/停止の動作を実現します。

Problem 6: Create a Vehicle class and define start_engine() and stop_engine() methods. Inherit Car and Motorcycle classes from Vehicle and override their respective methods to achieve different engine start/stop behaviors.

class Vehicle:
    def __init__(self, model):
        """コンストラクタ:モデルを設定する"""
        self.model = model
        self.engine_running = False

    def start_engine(self):
        """エンジン始動メソッド"""
        if not self.engine_running:
            print(f"Starting engine of {self.model}")
            self.engine_running = True
        else:
            print(f"Engine of {self.model} is already running.")

    def stop_engine(self):
        """エンジン停止メソッド"""
        if self.engine_running:
            print(f"Stopping engine of {self.model}")
            self.engine_running = False
        else:
            print(f"Engine of {self.model} is already stopped.")

class Car(Vehicle):
    def start_engine(self):
        """車のエンジン始動方法"""
        super().start_engine()  # Call the parent class's method
        print("Turning key and starting...")

class Motorcycle(Vehicle):
    def start_engine(self):
        """バイクのエンジン始動方法"""
        super().start_engine()
        print("Pressing starter button...")

# 使用例
my_car = Car("Toyota Camry")
my_motorcycle = Motorcycle("Harley Davidson Sportster")

my_car.start_engine() # Output: Starting engine of Toyota Camry Turning key and starting...
my_motorcycle.start_engine() # Output: Starting engine of Harley Davidson Sportster Pressing starter button...

メソッドの練習問題:発展編

Practice Problems: Advanced Level

以下に、メソッドのより高度な使い方を理解するための練習問題をいくつか紹介します。 これらの問題は、クラス設計とオブジェクト指向プログラミングの概念に対する深い理解が必要です。

Here are some practice problems to help you understand more advanced usage of methods. These problems require a deep understanding of class design and object-oriented programming concepts.

問題 7: Polynomial クラスを作成し、多項式の係数を持つリストを属性として持ちます。 evaluate(x) メソッドを実装して、与えられた x の値に対する多項式を評価するようにします。

Problem 7: Create a Polynomial class that has a list of coefficients as an attribute. Implement an evaluate(x) method to evaluate the polynomial for a given value of x.

class Polynomial:
    def __init__(self, coefficients):
        """コンストラクタ:係数のリストを設定する"""
        self.coefficients = coefficients  # Example: [1, 2, 3] represents 1 + 2x + 3x^2

    def evaluate(self, x):
        """多項式を評価するメソッド"""
        result = 0
        for i, coeff in enumerate(self.coefficients):
            result += coeff * (x**i)
        return result

# 使用例
poly = Polynomial([1, 2, 3])  # Represents the polynomial 1 + 2x + 3x^2
print(f"Polynomial evaluated at x=2: {poly.evaluate(2)}") # Output: Polynomial evaluated at x=2: 17

問題 8: Stack クラスを作成し、要素を格納するためのリストを属性として持ちます。 push(item) メソッドで要素を追加し、 pop() メソッドで要素を取り出し、 peek() メソッドで最上位の要素を確認できるようにします。 スタックが空の場合に pop() または peek() を呼び出された場合の例外処理も実装してください。

Problem 8: Create a Stack class that has a list as an attribute to store elements. Implement push(item) to add an element, pop() to remove an element, and peek() to view the top element. Also implement exception handling for when pop() or peek() are called on an empty stack.

class Stack:
    def __init__(self):
        """コンストラクタ:要素を格納するためのリストを初期化する"""
        self.items = []

    def push(self, item):
        """要素を追加するメソッド"""
        self.items.append(item)

    def pop(self):
        """要素を取り出すメソッド。スタックが空の場合は例外を発生させる"""
        if not self.is_empty():
            return self.items.pop()
        else:
            raise IndexError("Cannot pop from an empty stack")

    def peek(self):
        """最上位の要素を確認するメソッド。スタックが空の場合は例外を発生させる"""
        if not self.is_empty():
            return self.items[-1]
        else:
            raise IndexError("Cannot peek at an empty stack")

    def is_empty(self):
        """スタックが空かどうかを確認するメソッド"""
        return len(self.items) == 0

# 使用例
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)

print(f"Top element: {stack.peek()}") # Output: Top element: 3
print(f"Popped element: {stack.pop()}") # Output: Popped element: 3

問題 9: BinaryTree クラスを作成し、ノードを格納するためのリストを属性として持ちます。 各ノードは、値と左右の子ノードへの参照を持つようにします。 insert_node(value) メソッドで新しいノードを追加し、 inorder_traversal() メソッドで木をインオーダー順に走査して、すべての値を表示するようにします。

Problem 9: Create a BinaryTree class that has a list as an attribute to store nodes. Each node should have a value and references to its left and right child nodes. Implement an insert_node(value) method to add new nodes and an inorder_traversal() method to traverse the tree in inorder and display all values. (Note: Implementing a full binary tree with pointers is complex without using classes for nodes. This example uses a simplified list-based representation.)

class BinaryTree:
    def __init__(self):
        """コンストラクタ:ノードを格納するためのリストを初期化する"""
        self.nodes = []  # Simplified representation - not actual node objects

    def insert_node(self, value):
        """新しいノードを追加するメソッド (簡略化された実装)"""
        self.nodes.append(value)

    def inorder_traversal(self):
        """木をインオーダー順に走査して、すべての値を表示するメソッド (簡略化された実装)"""
        if self.nodes:
            print(self.nodes[0])  # Inorder traversal is not fully implemented in this simplified version

# 使用例
tree = BinaryTree()
tree.insert_node(1)
tree.insert_node(2)
tree.insert_node(3)
tree.inorder_traversal() # Output: 1 (Simplified - doesn't perform a full inorder traversal)

問題 10: Graph クラスを作成し、ノードとエッジを格納するための辞書を属性として持ちます。 add_edge(node1, node2) メソッドで新しいエッジを追加し、 get_neighbors(node) メソッドで指定されたノードの隣接ノードを取得するようにします。

Problem 10: Create a Graph class that has a dictionary as an attribute to store nodes and edges. Implement an add_edge(node1, node2) method to add new edges and a get_neighbors(node) method to retrieve the adjacent nodes of a given node.

class Graph:
    def __init__(self):
        """コンストラクタ:ノードとエッジを格納するための辞書を初期化する"""
        self.graph = {}  # Adjacency list representation

    def add_edge(self, node1, node2):
        """新しいエッジを追加するメソッド"""
        if node1 not in self.graph:
            self.graph[node1] = []
        if node2 not in self.graph:
            self.graph[node2] = []

        self.graph[node1].append(node2)
        # Assuming undirected graph, add the reverse edge as well
        self.graph[node2].append(node1)

    def get_neighbors(self, node):
        """指定されたノードの隣接ノードを取得するメソッド"""
        if node in self.graph:
            return self.graph[node]
        else:
            return []

# 使用例
graph = Graph()
graph.add_edge("A", "B")
graph.add_edge("A", "C")
graph.add_edge("B", "D")

print(f"Neighbors of A: {graph.get_neighbors('A')}") # Output: Neighbors of A: ['B', 'C']

これらの練習問題を解くことで、Python におけるメソッドの理解を深め、オブジェクト指向プログラミングのスキルを向上させることができます。 頑張ってください!

By solving these practice problems, you can deepen your understanding of methods in Python and improve your object-oriented programming skills. Good luck!