はじめに #
Pythonで作成したコードのクラス図を、Pyreverseを使って自動生成する方法を解説します。クラス図とは、クラスの属性やメソッド、およびクラス間の関係を示す以下のような図のことです。
この記事で検証した環境は以下の通りです。
- OS: Windows 10 Home
- Python 3.11.6
- Pylint 3.0.2
- Graphviz(Pythonライブラリ) 0.20.1
- Graphviz(本体) 2.46.1
PyreverseはPylintというライブラリに含まれています。また、Graphvizはクラス図を画像として出力するために必要であり、Windows用のソフト本体と、Pythonのインターフェースとしてのライブラリの両方をインストールします。
この記事はPython Advent Calendar 2023 (Qiita) 13日目の記事です。
インストール #
Pythonは既にインストールされていることを前提とします。以下のコマンドを実行して、Pylint(Pyreverseも含まれています)とGraphviz(Pythonライブラリ)をインストールします。
> pip install pylint
> pip install graphviz
次に、Graphvizの公式サイトからインストーラを入手して、Graphvizの本体をインストールします。 https://graphviz.org/download/
インストール中にパスを通すか聞かれるので、通しておきます。以下の画面で"Add Graphviz to the system PATH for all users"または"current user"を選択します。
Graphvizのインストール後、PowerShellまたはコマンドプロンプトで以下のコマンドを実行します。Graphvizにパスが通っていれば、バージョン番号が表示されます。
> dot -V
dot - graphviz version 2.46.0 (20210118.1747)
クラス図の作成例 #
まず、クラスが1つだけのPythonスクリプトを例に、Pyreverseを使ってクラス図を出力します。以下のスクリプトでは、Person
というクラスが定義されています。これをsingle_class.py
という名前を付けて保存します。
class Person:
def __init__(self, name):
self.name = name
def greet(self):
print(f"I'm {self.name}.")
次に、single_class.py
と同じディレクトリで以下のコマンドを実行します。
> pyreverse -o png -p single single_class.py
Format png is not supported natively. Pyreverse will try to generate it using Graphviz...
ここで、-o
オプションで出力形式、-p
オプションで出力するファイル名の接尾辞を指定します。コマンドの実行後、以下のクラス図がclasses_single.png
というファイル名で出力されます。
上から順に、クラスの以下の情報が表示されています。
- クラス名
- 属性
- メソッド
クラス間の関係 #
クラス間の関係として継承(汎化)、集約、コンポジションについて、それぞれクラス図として出力する例を示します。
継承(汎化) #
継承とは、あるクラスの特性(属性やメソッドなど)を別のクラスに引き継ぐことです。以下のスクリプトをinheritance.py
として保存します。先ほどのPerson
クラスを継承したEmployee
クラスを定義しています。
class Person:
def __init__(self, name):
self.name = name
def greet(self):
print(f"I'm {self.name}.")
class Employee(Person):
def __init__(self, name, company):
super().__init__(name)
self.company = company
def greet2(self):
print(f"I'm {self.name} from {self.company}.")
以下のコマンドを実行して、クラス図を出力します。
> pyreverse -o png -p inheritance inheritance.py
Person
クラスとEmployee
クラスが白い三角の矢印で結ばれており、継承(汎化)関係が出力されています。
集約 #
集約とは、以下のようなクラス間の関係です。
- あるクラスが別のクラスの「部分」として表される
- 全体のインスタンスが破棄されても、部分インスタンスが破棄されるとは限らない
以下のスクリプトaggregation.py
を作成します。Company
クラスのpresident
属性はPerson
インスタンスとなります。すなわち、Person
クラスはCompany
クラスの「部分」となります。また、型ヒントを使って、person
引数はPerson
インスタンスであることを示しています。
class Person:
def __init__(self, name):
self.name = name
def greet(self):
print(f"I'm {self.name}.")
class Company:
def __init__(self, company_name, person:Person):
self.company_name = company_name
self.president = person
以下のコマンドを実行して、クラス図を出力します。
> pyreverse -o png -p aggregation aggregation.py
Person
クラスとCompany
クラスが白い菱形の矢印で結ばれており、集約関係が出力されています。矢印の緑の文字は、Person
クラスがCompany
クラスのpresident
属性になることを示しています。
コンポジション #
コンポジションとは、以下のようなクラス間の関係です。
- あるクラスが別のクラスの「部分」として表される
- 全体のインスタンスが破棄されると、部分インスタンスも破棄される
以下のスクリプトcomposition.py
を作成します。Person
インスタンスの作成時に、Head
インスタンス (Person.head
) も作成されます。また、Person
インスタンスが破棄されるときにPerson.head
も破棄されるため、Head
クラスはPerson
クラスのコンポジションとなります。
class Head:
def __init__(self, wisdom:str):
self.wisdom = wisdom
class Person:
def __init__(self, name:str, wisdom:str):
self.name = name
self.head = Head(wisdom)
def greet(self):
print(f"I'm {self.name}.")
以下のコマンドを実行して、クラス図を出力します。
> pyreverse -o png -p composition composition.py
Person
クラスとHead
クラスが黒い菱形の矢印で結ばれており、コンポジション関係が出力されています。矢印の緑の文字は、Head
クラスがPerson
クラスのhead
属性になることを示しています。