ななぶろ

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

Pythonプログラム練習問題10問:クラスを活用する

www.amazon.co.jp

Python プログラム練習問題 10 問:クラスを活用する

Python の学習において、オブジェクト指向プログラミング (OOP) は非常に重要な概念です。OOP の中心となるのが「クラス」であり、データとそれを操作するメソッドをまとめることで、コードの再利用性、保守性、拡張性を高めます。

本記事では、Python のクラスを活用した練習問題を 10 問取り上げます。初心者の方でも理解しやすいように、各問題に対して丁寧な解説とサンプルコードを提供します。また、必要に応じて関連する Python ドキュメントや参考資料へのリンクも記載します。

クラスとは?

まず、クラスとは何かを簡単に説明します。クラスは、オブジェクトの設計図のようなものです。例えば、「犬」というクラスを定義すると、そのクラスから「ポチ」「タロウ」といった具体的な犬のオブジェクトを作成できます。各オブジェクトは、犬としての共通の特徴(名前、毛色、年齢など)を持ちながらも、それぞれ異なる個性を持ちます。

Python におけるクラスの基本的な構文は以下の通りです。

class クラス名:
    def __init__(self, 引数1, 引数2, ...):  # コンストラクタ
        self.属性1 = 引数1
        self.属性2 = 引数2
        ...

    def メソッド名(self, 引数1, 引数2, ...):
        # メソッドの処理
        return 戻り値
  • class: クラスを定義するためのキーワード。
  • クラス名: クラスの名前(例: Dog, Car, Rectangle)。
  • __init__(self, 引数1, 引数2, ...): コンストラクタと呼ばれる特別なメソッドで、オブジェクトが作成される際に自動的に呼び出されます。self は、そのオブジェクト自身を指します。コンストラクタでは、オブジェクトの属性(データ)を初期化します。
  • self.属性1 = 引数1: オブジェクトの属性を定義し、初期値を設定します。
  • メソッド名(self, 引数1, 引数2, ...): クラスに属する関数です。オブジェクトの状態を変更したり、特定の処理を実行するために使用されます。

What is a Class? (English Explanation)

A class in Python acts as a blueprint or template for creating objects. Think of it like a cookie cutter – the cutter defines the shape and characteristics of the cookies, but each individual cookie is an object created from that cutter. In programming terms, a class defines what data (attributes) an object will hold and what actions (methods) it can perform. For example, you could define a "Dog" class with attributes like name, breed, and age, and methods like bark() or fetch(). Then, you can create multiple Dog objects, each with its own unique values for those attributes.

練習問題と解説

それでは、クラスを活用した練習問題に取り組みましょう。

問題 1:シンプルな Dog クラスを作成する

犬の名前と種類を属性として持ち、紹介文を表示するメソッドを持つ Dog クラスを作成してください。

class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

    def introduce(self):
        print(f"こんにちは!私の名前は{self.name}、犬種は{self.breed}です。")

# Dog オブジェクトの作成とメソッド呼び出し
my_dog = Dog("ポチ", "柴犬")
my_dog.introduce()  # 出力: こんにちは!私の名前はポチ、犬種は柴犬です。

解説:

  • __init__(self, name, breed): コンストラクタで、namebreed を引数として受け取り、それぞれオブジェクトの属性 self.nameself.breed に代入しています。
  • introduce(self): 紹介文を表示するメソッドです。f-string を使用して、オブジェクトの属性を文字列に埋め込んでいます。

Problem 1: Create a Simple Dog Class (English Explanation)

This problem asks you to create a Dog class that has two attributes: name and breed. It also requires a method called introduce which prints a greeting message including the dog's name and breed.

The code defines a class named Dog. The __init__ method initializes the name and breed attributes of each Dog object. The introduce method uses an f-string to format and print a personalized introduction for the dog. Finally, it creates a Dog object called my_dog with the name "ポチ" (Pochi) and breed "柴犬" (Shiba Inu), then calls the introduce method to display its greeting.

問題 2:Rectangle クラスを作成し、面積を計算する

幅と高さを属性として持ち、面積を計算するメソッドを持つ Rectangle クラスを作成してください。

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def calculate_area(self):
        return self.width * self.height

# Rectangle オブジェクトの作成とメソッド呼び出し
my_rectangle = Rectangle(5, 10)
area = my_rectangle.calculate_area()
print(f"面積: {area}")  # 出力: 面積: 50

解説:

  • __init__(self, width, height): コンストラクタで、widthheight を引数として受け取り、それぞれオブジェクトの属性 self.widthself.height に代入しています。
  • calculate_area(self): 面積を計算するメソッドです。幅と高さの積を返します。

Problem 2: Create a Rectangle Class and Calculate Area (English Explanation)

This problem asks you to create a Rectangle class with attributes for width and height. It also requires a method called calculate_area that computes and returns the area of the rectangle.

The code defines a class named Rectangle. The __init__ method initializes the width and height attributes. The calculate_area method multiplies the width and height to calculate the area, which is then returned. An instance of the Rectangle class (my_rectangle) is created with dimensions 5x10, and its area is calculated using the calculate_area method. The result is printed to the console.

問題 3:BankAccount クラスを作成する (残高管理)

口座番号、所有者名、初期残高を属性として持ち、預金、引き出し、残高照会を行うメソッドを持つ BankAccount クラスを作成してください。

class BankAccount:
    def __init__(self, account_number, owner_name, initial_balance):
        self.account_number = account_number
        self.owner_name = owner_name
        self.balance = initial_balance

    def deposit(self, amount):
        self.balance += amount
        print(f"{amount}円を預金しました。現在の残高: {self.balance}円")

    def withdraw(self, amount):
        if self.balance >= amount:
            self.balance -= amount
            print(f"{amount}円を引き出しました。現在の残高: {self.balance}円")
        else:
            print("残高不足です。")

    def check_balance(self):
        print(f"現在の残高: {self.balance}円")

# BankAccount オブジェクトの作成とメソッド呼び出し
my_account = BankAccount("1234567890", "山田太郎", 10000)
my_account.deposit(5000)
my_account.withdraw(3000)
my_account.check_balance()

解説:

  • __init__(self, account_number, owner_name, initial_balance): コンストラクタで、口座番号、所有者名、初期残高を引数として受け取り、それぞれオブジェクトの属性 self.account_number, self.owner_name, self.balance に代入しています。
  • deposit(self, amount): 預金処理を行うメソッドです。残高に金額を加算し、メッセージを表示します。
  • withdraw(self, amount): 引き出し処理を行うメソッドです。残高が金額以上であれば、残高から金額を減算し、メッセージを表示します。そうでなければ、「残高不足です。」と表示します。
  • check_balance(self): 残高照会処理を行うメソッドです。現在の残高を表示します。

Problem 3: Create a BankAccount Class (Balance Management) (English Explanation)

This problem requires you to create a BankAccount class with attributes for account number, owner name, and initial balance. It also needs methods for depositing funds, withdrawing funds, and checking the balance.

The code defines a class named BankAccount. The __init__ method initializes the account number, owner name, and balance attributes. The deposit method adds an amount to the balance and prints a confirmation message. The withdraw method checks if there are sufficient funds before subtracting the withdrawal amount from the balance; otherwise, it displays an "Insufficient Funds" message. Finally, the check_balance method simply prints the current balance. An instance of the BankAccount class (my_account) is created with specific details and then used to perform deposit, withdrawal, and balance check operations.

問題 4:Employee クラスを作成する (給与計算)

社員番号、氏名、基本給を属性として持ち、残業時間に応じて給与を計算するメソッドを持つ Employee クラスを作成してください。残業時間は1時間あたり1500円とします。

class Employee:
    def __init__(self, employee_id, name, base_salary):
        self.employee_id = employee_id
        self.name = name
        self.base_salary = base_salary

    def calculate_salary(self, overtime_hours):
        overtime_pay = overtime_hours * 1500
        total_salary = self.base_salary + overtime_pay
        return total_salary

# Employee オブジェクトの作成とメソッド呼び出し
employee1 = Employee("E001", "佐藤花子", 250000)
salary = employee1.calculate_salary(10)
print(f"{employee1.name}さんの給与: {salary}円")  # 出力: 佐藤花子さんの給与: 315000円

解説:

  • __init__(self, employee_id, name, base_salary): コンストラクタで、社員番号、氏名、基本給を引数として受け取り、それぞれオブジェクトの属性 self.employee_id, self.name, self.base_salary に代入しています。
  • calculate_salary(self, overtime_hours): 残業時間に応じて給与を計算するメソッドです。残業代を計算し、基本給に加算して合計給与を返します。

Problem 4: Create an Employee Class (Salary Calculation) (English Explanation)

This problem asks you to create an Employee class with attributes for employee ID, name, and base salary. It also requires a method called calculate_salary that calculates the total salary based on overtime hours (with an hourly rate of 1500 yen).

The code defines a class named Employee. The __init__ method initializes the employee ID, name, and base salary attributes. The calculate_salary method calculates overtime pay by multiplying the number of overtime hours by 1500, then adds it to the base salary to determine the total salary, which is returned. An instance of the Employee class (employee1) is created with specific details, and its salary is calculated using the calculate_salary method for a given number of overtime hours. The result is printed to the console.

問題 5:Circle クラスを作成する (面積と円周の計算)

半径を属性として持ち、面積と円周を計算するメソッドを持つ Circle クラスを作成してください。円周率 π は math.pi を使用してください。

import math

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def calculate_area(self):
        return math.pi * self.radius ** 2

    def calculate_circumference(self):
        return 2 * math.pi * self.radius

# Circle オブジェクトの作成とメソッド呼び出し
my_circle = Circle(5)
area = my_circle.calculate_area()
circumference = my_circle.calculate_circumference()
print(f"面積: {area}, 円周: {circumference}")

解説:

  • __init__(self, radius): コンストラクタで、半径を引数として受け取り、オブジェクトの属性 self.radius に代入しています。
  • calculate_area(self): 面積を計算するメソッドです。円周率 π を math.pi から取得し、半径の2乗に掛けて面積を計算します。
  • calculate_circumference(self): 円周を計算するメソッドです。円周率 π と半径を用いて円周を計算します。

Problem 5: Create a Circle Class (Area and Circumference Calculation) (English Explanation)

This problem requires you to create a Circle class with a radius attribute, and methods for calculating the area and circumference of the circle. Use math.pi for the value of pi.

The code defines a class named Circle. The __init__ method initializes the radius attribute. The calculate_area method calculates the area using the formula π * r2, where r is the radius. The calculate_circumference method calculates the circumference using the formula 2 * π * r. An instance of the Circle class (my_circle) is created with a specific radius, and its area and circumference are calculated and printed to the console.

問題 6:クラスの継承を利用する (Animal と Dog)

Animal クラスを定義し、名前と鳴き声を属性として持ちます。次に、Dog クラスを Animal クラスを継承して作成し、犬種を追加します。Dog クラスには、紹介文を表示するメソッドを作成してください。

class Animal:
    def __init__(self, name, sound):
        self.name = name
        self.sound = sound

    def make_sound(self):
        print(f"{self.name} は {self.sound} と鳴きます。")

class Dog(Animal):
    def __init__(self, name, breed, sound="わん"):  # Animalの引数に加えて犬種を追加
        super().__init__(name, sound) # 親クラスのコンストラクタを呼び出す
        self.breed = breed

    def introduce(self):
        print(f"こんにちは!私の名前は{self.name}、犬種は{self.breed}です。鳴き声は {self.sound} です。")

# Dog オブジェクトの作成とメソッド呼び出し
my_dog = Dog("ポチ", "柴犬")
my_dog.introduce()  # 出力: こんにちは!私の名前はポチ、犬種は柴犬です。鳴き声は わん です。
my_dog.make_sound() # 出力: ポチ は わん と鳴きます。

解説:

  • Animal クラス: 名前と鳴き声を属性として持ち、鳴き声を出すメソッド make_sound() を持ちます。
  • Dog(Animal): Animal クラスを継承したクラスです。犬種を追加し、紹介文を表示するメソッド introduce() を持ちます。
  • super().__init__(name, sound): 親クラス (Animal) のコンストラクタを呼び出して、名前と鳴き声を初期化します。

Problem 6: Using Class Inheritance (Animal and Dog) (English Explanation)

This problem requires you to define an Animal class with attributes for name and sound. Then, create a Dog class that inherits from the Animal class and adds a breed attribute. The Dog class should also have a method to display an introduction message.

The code defines an Animal class with attributes for name and sound, and a method called make_sound. A Dog class is then created by inheriting from the Animal class. It adds a breed attribute and includes an introduce method that displays an introductory message including the dog's name, breed, and sound. The super().__init__(name, sound) call within the Dog constructor ensures that the parent class's initialization logic is executed correctly. An instance of the Dog class (my_dog) is created with specific details and used to demonstrate both the inherited make_sound method and the custom introduce method.

問題 7:クラスの継承を利用する (Vehicle と Car)

Vehicle クラスを定義し、メーカーとモデルを属性として持ちます。次に、Car クラスを Vehicle クラスを継承して作成し、ドア数を追加します。Car クラスには、詳細情報を表示するメソッドを作成してください。

class Vehicle:
    def __init__(self, manufacturer, model):
        self.manufacturer = manufacturer
        self.model = model

    def display_info(self):
        print(f"メーカー: {self.manufacturer}, モデル: {self.model}")

class Car(Vehicle):
    def __init__(self, manufacturer, model, num_doors):
        super().__init__(manufacturer, model)
        self.num_doors = num_doors

    def display_details(self):
        super().display_info() # 親クラスのメソッドを呼び出す
        print(f"ドア数: {self.num_doors}")

# Car オブジェクトの作成とメソッド呼び出し
my_car = Car("トヨタ", "カローラ", 4)
my_car.display_details()  # 出力: メーカー: トヨタ, モデル: カローラ、ドア数: 4

解説:

  • Vehicle クラス: メーカーとモデルを属性として持ち、基本的な情報を表示するメソッド display_info() を持ちます。
  • Car(Vehicle): Vehicle クラスを継承したクラスです。ドア数を追加し、詳細情報を表示するメソッド display_details() を持ちます。
  • super().display_info(): 親クラス (Vehicle) のメソッド display_info() を呼び出して、メーカーとモデルを表示します。

Problem 7: Using Class Inheritance (Vehicle and Car) (English Explanation)

This problem requires you to define a Vehicle class with attributes for manufacturer and model. Then, create a Car class that inherits from the Vehicle class and adds a number of doors attribute. The Car class should have a method to display detailed information.

The code defines a Vehicle class with attributes for manufacturer and model, and a method called display_info. A Car class is then created by inheriting from the Vehicle class. It adds a num_doors attribute and includes a display_details method that calls the parent's display_info method using super().display_info() to display the manufacturer and model, followed by the number of doors. An instance of the Car class (my_car) is created with specific details and used to demonstrate the inherited and custom methods.

問題 8:クラスの継承とオーバーライド (Shape と Circle)

Shape クラスを定義し、面積を計算する抽象メソッド calculate_area() を持ちます。次に、Circle クラスを Shape クラスを継承して作成し、半径を属性として持ち、calculate_area() メソッドをオーバーライドして、円の面積を計算するようにします。

import math

class Shape:
    def calculate_area(self):
        raise NotImplementedError("サブクラスで実装してください")  # 抽象メソッド

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def calculate_area(self):
        return math.pi * self.radius ** 2

# Circle オブジェクトの作成とメソッド呼び出し
my_circle = Circle(5)
area = my_circle.calculate_area()
print(f"面積: {area}")  # 出力: 面積: 78.53981633974483

解説:

  • Shape クラス: calculate_area() メソッドを定義していますが、これは抽象メソッドです。サブクラスで必ずオーバーライドする必要があります。
  • Circle(Shape): Shape クラスを継承したクラスです。半径を属性として持ち、calculate_area() メソッドをオーバーライドして、円の面積を計算します。
  • raise NotImplementedError("サブクラスで実装してください"): 抽象メソッドは、基底クラスで具体的な実装を持たず、派生クラスに実装を強制するために使用されます。

Problem 8: Class Inheritance and Overriding (Shape and Circle) (English Explanation)

This problem requires you to define a Shape class with an abstract method called calculate_area. Then, create a Circle class that inherits from the Shape class, adds a radius attribute, and overrides the calculate_area method to calculate the area of a circle.

The code defines a Shape class with a calculate_area method that raises a NotImplementedError, making it an abstract method. A Circle class is then created by inheriting from the Shape class. It adds a radius attribute and overrides the calculate_area method to calculate the area of a circle using the formula π * r2. The use of raise NotImplementedError in the base class enforces that subclasses must provide their own implementation of this method. An instance of the Circle class (my_circle) is created with a specific radius, and its area is calculated and printed to the console.

問題 9:クラスのメソッドと静的メソッド (MathHelper)

数学的な計算を行うための MathHelper クラスを作成します。このクラスには、2つの数の合計を計算するインスタンスメソッド add() と、クラス変数を使用して2つの数の積を計算する静的メソッド multiply() を含めます。

class MathHelper:
    # クラス変数
    multiplier = 2

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def add(self):
        return self.x + self.y

    @staticmethod
    def multiply(x, y):
        return x * y * MathHelper.multiplier  # クラス変数を使用

# MathHelper オブジェクトの作成とメソッド呼び出し
helper = MathHelper(5, 3)
sum_result = helper.add()
product_result = MathHelper.multiply(5, 3)
print(f"合計: {sum_result}, 積: {product_result}")  # 出力: 合計: 8, 積: 30

解説:

  • multiplier: クラス変数です。クラスのすべてのインスタンスで共有されます。
  • add(): インスタンスメソッドです。オブジェクトの状態 (self.x, self.y) を使用して計算を行います。
  • @staticmethod: デコレータです。静的メソッドであることを示します。静的メソッドは、クラスのインスタンスに依存せず、クラス自体に関連付けられます。
  • MathHelper.multiplier: クラス変数にアクセスするために使用します。

Problem 9: Class Methods and Static Methods (MathHelper) (English Explanation)

This problem requires you to create a MathHelper class for performing mathematical calculations. The class should include an instance method called add that calculates the sum of two numbers, and a static method called multiply that uses a class variable to calculate the product of two numbers.

The code defines a MathHelper class with a class variable multiplier. It includes an instance method add that takes the object's attributes (self.x, self.y) as input and calculates their sum. It also includes a static method multiply decorated with @staticmethod. Static methods are associated with the class itself rather than instances of the class, and they can access class variables like MathHelper.multiplier. An instance of MathHelper is created, and both methods are called to demonstrate their usage.

問題 10:クラスのプロパティ (TemperatureConverter)

摂氏温度を属性として持ち、華氏温度に変換するゲッターメソッドと、華氏温度から摂氏温度に変換するセッターメソッドを持つ TemperatureConverter クラスを作成してください。

class TemperatureConverter:
    def __init__(self, celsius):
        self._celsius = celsius  # 属性をプライベートにする

    @property
    def fahrenheit(self):
        return (self._celsius * 9/5) + 32

    @fahrenheit.setter
    def fahrenheit(self, fahrenheit_temp):
        self._celsius = (fahrenheit_temp - 32) * 5/9

# TemperatureConverter オブジェクトの作成とメソッド呼び出し
converter = TemperatureConverter(25)
print(f"摂氏: {converter._celsius}, 華氏: {converter.fahrenheit}")  # 出力: 摂氏: 25, 華氏: 77.0

converter.fahrenheit = 68
print(f"華氏: {converter.fahrenheit}, 摂氏: {converter._celsius}") # 出力: 華氏: 68.0, 摂氏: 20.0

解説:

  • _celsius: プライベート属性です。アンダースコア _ で始まる属性は、外部からの直接アクセスを避けることを推奨します。
  • @property: デコレータです。fahrenheit 属性にアクセスすると、get_fahrenheit() メソッドが自動的に呼び出されます。
  • @fahrenheit.setter: デコレータです。converter.fahrenheit = value のように fahrenheit 属性に値を設定すると、set_fahrenheit(value) メソッドが自動的に呼び出されます。

Problem 10: Class Properties (TemperatureConverter) (English Explanation)

This problem requires you to create a TemperatureConverter class with a Celsius temperature attribute, a getter method for converting to Fahrenheit, and a setter method for converting from Fahrenheit back to Celsius.

The code defines a TemperatureConverter class with a private attribute _celsius. It uses the @property decorator to define a getter method for the fahrenheit attribute, which converts Celsius to Fahrenheit. It also uses the @fahrenheit.setter decorator to define a setter method that takes a Fahrenheit temperature as input and converts it back to Celsius, updating the _celsius attribute accordingly. This allows you to access and modify the temperature using the fahrenheit property in a more intuitive way.