Menu
Coddy logo textTech

静的メソッドとクラスメソッド

CoddyのPythonジャーニー「Object Oriented Programming」セクションの一部 — レッスン 39/64。

通常のインスタンスメソッドに加えて、クラスは異なる目的で使用される静的メソッドやクラスメソッドを持つことができます。

以下は静的メソッドの例です。

class MathHelper:
    @staticmethod
    def add(a, b):
        return a + b
    
    @staticmethod
    def is_even(number):
        return number % 2 == 0

静提メソッドは self を必要とせず、通常の関数のように動作します。これらはクラスから直接呼び出します:

result = MathHelper.add(5, 3)
print(result)

check = MathHelper.is_even(10)
print(check)

クラスメソッドの例を次に示します:

class Person:
    count = 0  # クラス変数
    
    def __init__(self, name):
        self.name = name
        Person.count += 1
    
    @classmethod
    def get_count(cls):
        return cls.count
    
    @classmethod
    def create_anonymous(cls):
        return cls("Anonymous")

クラスメソッドは、クラス自体(cls)を第1引数として受け取ります:

person1 = Person("Alice")
person2 = Person("Bob")
print(Person.get_count())  # 2

クラスメソッドを代替のコンストラクタとして使用します:

anonymous = Person.create_anonymous()
print(anonymous.name)      # 匿名
print(Person.get_count())  # 3

1つのクラス内で3つのメソッドタイプすべてを比較します:

class Calculator:
    brand = "Python Calc"
    
    def __init__(self, owner):
        self.owner = owner
    
    # インスタンスメソッド - selfが必要で、インスタンスデータにアクセスします
    def show_owner(self):
        return f"Owned by {self.owner}"
    
    # クラスメソッド - clsが必要で、クラスデータにアクセスします
    @classmethod
    def get_brand(cls):
        return cls.brand
    
    # スタティックメソッド - どちらも不要で、単なるユーティリティ関数です
    @staticmethod
    def multiply(x, y):
        return x * y
calc = Calculator("Alice")
print(calc.show_owner())        # 所有者: Alice
print(Calculator.get_brand())   # Python Calc
print(Calculator.multiply(4, 5)) # 20

出力:

8
True
2
Anonymous
3
Owned by Alice
Python Calc
20

インスタンスからクラスメソッドや静的メソッドを呼び出すこともできます:

calc = Calculator("Bob")
print(calc.get_brand())      # Python Calc
print(calc.multiply(2, 3))   # 6

主な違い:

  • インスタンスメソッド: self を必要とし、インスタンスデータにアクセスします
  • クラスメソッド: cls を必要とし、クラスデータにアクセスします。代替コンストラクタに適しています
  • スタティックメソッド: どちらも必要とせず、クラスに関連する単なるユーティリティ関数です

重要なポイント: クラスに論理的に属しているが、クラスやインスタンスのデータを必要としないユーティリティ関数には @staticmethod を使用します。代替コンストラクタやクラス変数へのアクセスなど、クラス自体にアクセスする必要がある場合は @classmethod を使用します。

challenge icon

チャレンジ

簡単

このチャレンジでは、包括的なテストフレームワークを活用しながら、特定の機能を備えた Temperature クラスを実装します。

実装のガイドとなる TODO コメントに従って、temperature.py ファイルのみを編集する必要があります。このクラスには以下を含める必要があります:

  • 温度の読み取り値を追跡するためのクラス変数
  • 温度変換のための静的メソッド
  • 読み取り値の追加と平均値の計算のためのクラスメソッド

チートシート

クラスには、インスタンスメソッド、スタティックメソッド、クラスメソッドの3種類のメソッドがあります。

スタティックメソッドは、@staticmethodデコレータを使用し、selfを必要とせず、通常の関数のように動作します:

class MathHelper:
    @staticmethod
    def add(a, b):
        return a + b

# クラスから直接呼び出す
result = MathHelper.add(5, 3)

クラスメソッドは、@classmethodデコレータを使用し、最初のパラメータとしてクラス(cls)を受け取ります:

class Person:
    count = 0
    
    def __init__(self, name):
        self.name = name
        Person.count += 1
    
    @classmethod
    def get_count(cls):
        return cls.count
    
    @classmethod
    def create_anonymous(cls):
        return cls("Anonymous")

# 使用例
print(Person.get_count())
anonymous = Person.create_anonymous()

主な違い:

  • インスタンスメソッドselfが必要で、インスタンスデータにアクセスします
  • クラスメソッドclsが必要で、クラスデータにアクセスします。代替コンストラクタに適しています
  • スタティックメソッド:どちらも不要で、クラスに関連する単なるユーティリティ関数です

クラスメソッドとスタティックメソッドはどちらも、クラスまたはインスタンスから呼び出すことができます:

Calculator.multiply(4, 5)  # クラスから
calc.multiply(4, 5)        # インスタンスから

自分で試してみよう

from temperature import Temperature

# 包括的なテストのためのテストケースハンドラー
test_case = input()

if test_case == "default_test":
    # 基本的な機能をテスト
    Temperature.celsius_readings = []
    Temperature.add_reading(25)
    Temperature.add_reading(30)
    Temperature.add_reading(27)
    
    print(f"Average reading: {Temperature.average_reading()}")
    print(f"22°C is {Temperature.celsius_to_fahrenheit(22)}°F")

elif test_case == "empty_readings":
    # 測定値がない場合の average_reading をテスト
    Temperature.celsius_readings = []
    print(f"Average reading: {Temperature.average_reading()}")

elif test_case == "single_reading":
    # 単一の測定値でテスト
    Temperature.celsius_readings = []
    Temperature.add_reading(100)
    print(f"Average reading: {Temperature.average_reading()}")

elif test_case == "negative_values":
    # 負の温度値でテスト
    Temperature.celsius_readings = []
    Temperature.add_reading(-10)
    Temperature.add_reading(-20)
    Temperature.add_reading(-30)
    print(f"Average reading: {Temperature.average_reading()}")
    print(f"-15°C is {Temperature.celsius_to_fahrenheit(-15)}°F")

elif test_case == "zero_value":
    # 0°Cの測定値でテスト
    print(f"0°C is {Temperature.celsius_to_fahrenheit(0)}°F")

elif test_case == "extreme_values":
    # 極端な温度値でテスト
    absolute_zero = -273.15  # 摂氏での絶対零度
    sun_surface = 5500  # 摂氏での太陽表面のおおよその温度
    
    print(f"{absolute_zero}°C is {Temperature.celsius_to_fahrenheit(absolute_zero)}°F")
    print(f"{sun_surface}°C is {Temperature.celsius_to_fahrenheit(sun_surface)}°F")

elif test_case == "reset_readings":
    # 測定値のリセットをテスト
    Temperature.celsius_readings = []
    Temperature.add_reading(10)
    Temperature.add_reading(20)
    Temperature.add_reading(30)
    print(f"Average reading before reset: {Temperature.average_reading()}")
    
    Temperature.celsius_readings = []
    print(f"Average reading after reset: {Temperature.average_reading()}")

elif test_case == "decimal_values":
    # 小数値でテスト
    Temperature.celsius_readings = []
    Temperature.add_reading(36.5)  # 平熱
    Temperature.add_reading(37.2)  # 微熱
    Temperature.add_reading(36.9)  # 通常の変動
    print(f"Average reading: {Temperature.average_reading()}")

elif test_case == "many_readings":
    # 多数の測定値でテスト
    Temperature.celsius_readings = []
    for i in range(1, 101):
        Temperature.add_reading(i)
    print(f"Average reading with 100 values: {Temperature.average_reading()}")
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Object Oriented Programmingのすべてのレッスン