Python 3: Deep Dive (Part 2 - Iterators, Generators): プロジェクト① (セクション3/14)
Pythonで正則厳密凸多角形を表す`Polygon`クラスを作成し、数学的特性(内角、辺長、面積など)を計算するメソッドを実装。
複数の`Polygon`オブジェクトを保持する`PolygonSequence`クラスを開発し、インデックス付けやスライシングなどのシーケンス操作をサポート。
これらのクラスの実装を通じて、Pythonのオブジェクト指向プログラミング、イテレータ、ジェネレータ、およびテスト技法の実践的な応用を学習。
Udemy の Python 3:Deep Dive(パート2 - イテレータ、ジェネレータ) コースのセクション3では、学習者がPythonのイテレータ、ジェネレータ、シーケンスプロトコルの理解を適用するための興味深いプロジェクトが提示されています。このプロジェクトでは、`Polygon`クラスと、一連の多角形を保持するカスタムシーケンスタイプを作成します。このブログ記事では、このプロジェクトに関連する概念、実装、テストについて探ります。
背景:正則厳密凸多角形
コードに深入りする前に、このプロジェクトの背景にある数学的概念を理解しましょう。
正則厳密凸多角形は、以下の条件を満たす多角形です:
正則:すべての辺の長さが等しく、すべての内角が等しい。
厳密凸:すべての内角が180度未満で、多角形が外側に膨らんでいて凹みがない。
このような多角形の主要な特性には以下が含まれます:
辺:多角形を構成する直線。
頂点:2つの辺が交わる点。
内角:多角形内部の隣接する2つの辺の間に形成される角度。
アポテム:多角形の中心から一つの辺に垂直な線。
外接円半径(R):多角形のすべての頂点を通過する外接円の半径。
重要な公式
n辺と外接円半径Rを持つ正則厳密凸多角形の場合:
内角:
[
\text{内角} = \frac{(n - 2) \times 180^\circ}{n}
]辺の長さ(s):
[
s = 2R \times \sin\left(\frac{\pi}{n}\right)
]アポテム(a):
[
a = R \times \cos\left(\frac{\pi}{n}\right)
]面積:
[
\text{面積} = \frac{1}{2} \times n \times s \times a
]周長:
[
\text{周長} = n \times s
]
目標1:`Polygon`クラスの作成
最初の目標は、正則厳密凸多角形の特性と動作をカプセル化する`Polygon`クラスを作成することです。
要件
イニシャライザ:辺の数(n)と外接円半径(R)を受け取る。
プロパティ:
頂点の数(`.count_vertices`)
辺の数(`.count_edges`)
内角(`.interior_angle`)
辺の長さ(`.edge_length`)
アポテム(`.apothem`)
面積(`.area`)
周長(`.perimeter`)
機能:
適切な文字列表現(`repr`)
等価比較(`eq`):頂点の数と外接円半径に基づく。
大なり比較(`gt`):頂点の数に基づく。
実装の概要
実装のアプローチは以下の通りです:
イニシャライザ:頂点の数と外接円半径を保存します。また、頂点の数が少なくとも3であることを確認するバリデーションチェックも含みます。
プロパティ:`@property`デコレータを使用して読み取り専用プロパティとして実装します。各プロパティは提供された公式に基づいて値を計算します。
マジックメソッド:
`repr`:多角形の文字列表現を返します。
`eq`:頂点の数と外接円半径に基づいて等価性をチェックします。
`gt`:頂点の数に基づいて多角形を比較します。
使用例
# 多角形の作成
polygon1 = Polygon(5, 10)
polygon2 = Polygon(7, 10)
# プロパティへのアクセス
print("辺の数:", polygon1.count_edges)
print("内角:", polygon1.interior_angle)
print("面積:", polygon1.area)
# 多角形の比較
print("Polygon1 == Polygon2:", polygon1 == polygon2)
print("Polygon1 > Polygon2:", polygon1 > polygon2)
`Polygon`クラスのテスト
クラスが期待通りに動作することを確認するためにテストは不可欠です。ユニットテストには`assert`文を使用しました。
サンプルテスト
def test_polygon():
n = 4
R = 1
polygon = Polygon(n, R)
assert polygon.count_vertices == n
assert polygon.count_edges == n
assert polygon.circumradius == R
assert math.isclose(polygon.interior_angle, 90)
assert math.isclose(polygon.area, 2.0, rel_tol=0.001)
既知の値でさまざまなプロパティをテストし、計算が正確であることを確認しました。また、3辺未満の多角形など、無効な入力が提供された場合の動作もチェックしました。
目標2:`PolygonSequence`クラスの作成
2つ目の目標は、インデックス付けやスライシングなどのシーケンスプロトコルをサポートする、`Polygon`オブジェクトのシリーズを保持するカスタムシーケンスタイプを作成することです。
要件
イニシャライザ:最大頂点数(m)とシーケンス内のすべての多角形に共通の外接円半径(R)を受け取ります。
シーケンスプロトコル:
インデックス付けをサポート(`getitem`)
長さクエリをサポート(`len`)
プロパティ:
`.max_efficiency_polygon`:面積対周長比が最も高い多角形を返します。
実装の概要
イニシャライザ:入力を検証し、3からm辺までの`Polygon`インスタンスのリストを作成します。
シーケンスプロトコル:
`len`:シーケンス内の多角形の数を返します。
`getitem`:基礎となる多角形のリストに委譲することで、インデックス付けとスライシングをサポートします。
最大効率多角形:
`.max_efficiency_polygon`プロパティは、各多角形の面積対周長比を計算し、最も高い比率を持つ多角形を返します。
使用例
# 多角形のシーケンスの作成
polygons = PolygonSequence(10, 10)
# インデックス付けによる多角形へのアクセス
print(polygons[0]) # 3辺の多角形
print(polygons[3]) # 6辺の多角形
# シーケンスの長さ
print("多角形の数:", len(polygons))
# シーケンスのスライシング
print(polygons[2:5]) # 5から7辺の多角形
# 最も効率的な多角形
print("最大効率多角形:", polygons.max_efficiency_polygon)
`PolygonSequence`クラスのテスト
シーケンスが標準的なPythonシーケンスのように動作し、カスタムプロパティが正しく機能することを確認しました。
サンプルテスト
def test_polygon_sequence():
polygons = PolygonSequence(5, 1)
assert len(polygons) == 3 # 3、4、5辺の多角形
# インデックス付けのテスト
assert polygons[0].count_edges == 3
assert polygons[2].count_edges == 5
# スライシングのテスト
sliced_polygons = polygons[1:3]
assert len(sliced_polygons) == 2
assert sliced_polygons[0].count_edges == 4
# 最大効率多角形のテスト
max_eff_poly = polygons.max_efficiency_polygon
assert max_eff_poly.count_edges == 5
洞察と学び
シーケンスプロトコル:`getitem`と`len`メソッドを実装することで、クラスがPythonシーケンスのように動作し、インデックス付け、スライシング、イテレーションなどの機能をサポートできるようになります。
不変性:プロパティにセッターを提供せず、プライベート変数(アンダースコア1つのプレフィックス付き)を使用することで、`Polygon`インスタンスが不変であることを確保しました。
`assert`を使用したテスト:ユニットテストに`assert`文を使用することで、早期にエラーを捕捉できます。浮動小数点数を扱う際は、精度の問題を考慮して`math.isclose()`を使用することが重要です。
演算子のオーバーロード:`eq`と`gt`を実装することで、カスタムオブジェクトに比較演算子(`==`と`>`)を使用できるようになり、コードがより直感的になります。
効率性の計算:面積対周長比は、特に辺の数が増えるにつれて円に近似する形状を考慮する際に、多角形を比較するための有用な指標です。
結論
このプロジェクトは、Pythonのオブジェクト指向機能、シーケンスプロトコル、そして徹底的なテストの重要性の実践的な適用を提供しました。`Polygon`と`PolygonSequence`クラスを作成することで、機能的でユーザーフレンドリーなクラスを設計する方法についてより深い理解を得ることができました。
Python 3:Deep Diveコースの学生であれ、スキルを向上させたいPython愛好家であれ、このようなプロジェクトは、クリーンで効率的、そしてテスト可能なコードを書くための貴重な洞察を提供します。
注:すべてのコード例は説明目的のものであり、コースで議論された実際の実装の簡略版です。