バイオインフォマティクスでは、Python3 のオブジェクト指向プログラミング(OOP)が非常に重要です。特に、大規模なデータ解析や機械学習を行う際、コードの再利用性や保守性を高めるために、クラスやデコレーターの概念を理解することが役立ちます。
本記事では、クラスデコレーター(Class Decorator) の基本的な仕組みから応用までを、バイオインフォマティクスでの活用を意識しながら解説していきます。
1. クラスデコレーターとは?
Python のデコレーターといえば、関数デコレーター(@staticmethod
や @property
など)が一般的ですが、クラスにもデコレーターを適用できます。
クラスデコレーターは、クラスを引数に取る関数 であり、新しいクラスを返すか、元のクラスを変更するものです。これを使うことで、クラスの振る舞いを動的に変更したり、ログやキャッシュ機能を追加したりできます。
基本の構造
def class_decorator(cls):
class NewClass(cls):
def new_method(self):
return "追加されたメソッド"
return NewClass
@class_decorator
class MyClass:
def original_method(self):
return "元のメソッド"
obj = MyClass()
print(obj.original_method()) # "元のメソッド"
print(obj.new_method()) # "追加されたメソッド"
このように、クラスデコレーターは元のクラスをラップする新しいクラスを作成することで、既存のクラスの振る舞いを拡張できます。
2. クラスデコレーターの応用 – ロギング機能の追加
バイオインフォマティクスでは、データの前処理や機械学習モデルの学習プロセスを可視化するために、ログを記録することが重要です。
クラスデコレーターを使うことで、すべてのメソッド呼び出しを記録する機能を簡単に追加できます。
ロギング用のクラスデコレーター
def log_methods(cls):
class Wrapped(cls):
def __getattribute__(self, name):
attr = super().__getattribute__(name)
if callable(attr): # メソッドの場合のみロギング
def new_func(*args, **kwargs):
print(f"[LOG] {cls.__name__}.{name} が呼ばれました")
return attr(*args, **kwargs)
return new_func
return attr
return Wrapped
@log_methods
class BioAnalyzer:
def analyze_dna(self, sequence):
return f"Analyzing DNA: {sequence}"
def analyze_protein(self, sequence):
return f"Analyzing Protein: {sequence}"
bio = BioAnalyzer()
print(bio.analyze_dna("AGCTGAC")) # ログ付きで出力
print(bio.analyze_protein("MVKLA")) # ログ付きで出力
出力例:
[LOG] BioAnalyzer.analyze_dna が呼ばれました
Analyzing DNA: AGCTGAC
[LOG] BioAnalyzer.analyze_protein が呼ばれました
Analyzing Protein: MVKLA
これにより、どのメソッドがどのタイミングで呼び出されたかを記録でき、デバッグや解析の可視化に役立ちます。
3. クラスデコレーターの応用 – キャッシュ機能の追加
バイオインフォマティクスの解析では、大量のデータを処理するため、同じ計算結果をキャッシュすることで効率を向上させることができます。
計算結果をキャッシュするクラスデコレーター
def cache_results(cls):
class CachedClass(cls):
_cache = {}
def __getattribute__(self, name):
attr = super().__getattribute__(name)
if callable(attr): # メソッドの場合のみキャッシュ
def new_func(*args, **kwargs):
key = (name, args, tuple(kwargs.items()))
if key not in self._cache:
self._cache[key] = attr(*args, **kwargs)
return self._cache[key]
return new_func
return attr
return CachedClass
@cache_results
class SequenceAnalyzer:
def gc_content(self, sequence):
"""DNA配列のGC含量を計算"""
gc_count = sequence.count("G") + sequence.count("C")
return gc_count / len(sequence)
analyzer = SequenceAnalyzer()
print(analyzer.gc_content("AGCTGAC")) # 計算実行
print(analyzer.gc_content("AGCTGAC")) # キャッシュされた結果を返す
キャッシュ機能を持つことで、同じDNA配列のGC含量を再計算せずに高速に取得できます。
4. クラスデコレーターの応用 – 計算時間の測定
バイオインフォマティクスの処理では、どの処理が時間がかかっているのかを把握することが重要です。
計算時間を測定するクラスデコレーター
import time
def measure_time(cls):
class TimedClass(cls):
def __getattribute__(self, name):
attr = super().__getattribute__(name)
if callable(attr): # メソッドの場合のみ時間測定
def new_func(*args, **kwargs):
start = time.time()
result = attr(*args, **kwargs)
end = time.time()
print(f"[TIME] {cls.__name__}.{name} 実行時間: {end - start:.5f} 秒")
return result
return new_func
return attr
return TimedClass
@measure_time
class LargeDataProcessor:
def process_data(self, data):
"""データを処理(シミュレーション)"""
time.sleep(1) # 計算の負荷をシミュレート
return f"Processed {len(data)} items"
processor = LargeDataProcessor()
print(processor.process_data(range(1000)))
出力例:
[TIME] LargeDataProcessor.process_data 実行時間: 1.00012 秒
Processed 1000 items
このように、処理時間を自動的に測定できるため、ボトルネックの特定に役立ちます。
5. まとめ
本記事では、クラスデコレーターの基本から応用まで をバイオインフォマティクスの文脈で紹介しました。
- 基本: クラスデコレーターの仕組みと拡張方法
- 応用:
- ロギング機能 – メソッドの呼び出しを記録
- キャッシュ機能 – 計算結果を保存して効率化
- 計算時間の測定 – ボトルネックを特定
バイオインフォマティクスでは、大規模なデータを扱うため、コードの保守性や計算効率の向上が重要です!!クラスデコレーターを活用して、柔軟で拡張性のあるプログラムを作成しましょう〜!