PyCharm リファクタリングチュートリアル
このチュートリアルの内容
このチュートリアルでは、有理数を利用する単純なクラスの例を使って、PyCharm で利用できるいくつかのリファクタリングを紹介します。
前提条件
次の前提条件が満たされていることを確認してください:
例の準備
プロジェクトに Python ファイル rational.py を作成し、次のコードを追加してください:
from collections import namedtuple
class Rational(namedtuple('Rational', ['num', 'denom'])):
def __new__(cls, num, denom):
if denom == 0:
raise ValueError('Denominator cannot be null')
if denom < 0:
num, denom = -num, -denom
return super().__new__(cls, num, denom)
def __str__(self):
return '{}/{}'.format(self.num, self.denom)
有理数を単純化する
分子と分母を最大公約数で除算して有理数を単純化しましょう:
from collections import namedtuple
class Rational(namedtuple('Rational', ['num', 'denom'])):
def __new__(cls, num, denom):
if denom == 0:
raise ValueError('Denominator cannot be null')
if denom < 0:
num, denom = -num, -denom
x = abs(num)
y = abs(denom)
while x:
x, y = y % x, x
factor = y
return super().__new__(cls, num // factor, denom // factor)
def __str__(self):
return '{}/{}'.format(self.num, self.denom)
メソッドの抽出
ここでは、最も大きな共通の除数の検索を別の方法に抽出しましょう。 これを行うには、ステートメントを選択します
x = abs(num)
y = abs(denom)
while x:
x, y = y % x, x
factor = y
そして Ctrl+Alt+M を押します。 開いた ダイアログでメソッド名 gcd を入力し、 OK をクリックします。
@staticmethod
def gcd(denom, num):
x = abs(num)
y = abs(denom)
while x:
x, y = y % x, x
factor = y
return factor
ローカル変数のインライン化とメソッドシグネチャーの変更
変数のインライン化リファクタリングを使って、変数 factor を取り除きましょう。 そのためには、変数にキャレットを置いて Ctrl+Alt+N を押します。 検出された factor 変数はすべてインライン化されています。
次に、 シグネチャーの変更 を使ってパラメーター名を変更します。 そのためには、メソッド宣言行にキャレットを置き、 Ctrl+F6 を押します。 開いた ダイアログで、パラメーター denom と num をそれぞれ x と y に名前変更し、
をクリックしてパラメーターの順序を変更します。
次のコードで終わります:
@staticmethod
def gcd(x, y):
x = abs(x)
y = abs(y)
while x:
x, y = y % x, x
return y
クイックフィックスの使用
既存の静的メソッドを関数に変換しましょう。 これを行うには、 Alt+Enter を押し、候補リストから static メソッドを関数に変換する を選択し、 Enter を押します:
from collections import namedtuple
class Rational(namedtuple('Rational', ['num', 'denom'])):
def __new__(cls, num, denom):
if denom == 0:
raise ValueError('Denominator cannot be null')
if denom < 0:
num, denom = -num, -denom
factor = gcd(num, denom)
return super().__new__(cls, num // factor, denom // factor)
def __str__(self):
return '{}/{}'.format(self.num, self.denom)
def gcd(x, y):
x = abs(x)
y = abs(y)
while x:
x, y = y % x, x
return y
関数を別のファイルに移動する
それでは、関数を別のファイルに移動して import ステートメントを追加します。 そのためには、関数 gcd 宣言にキャレットを置き、 F6 を押します。 開いた ダイアログで、宛先ファイル util.py の完全修飾パスを指定します。 このファイルは存在しませんが、自動的に作成されます。
def gcd(x, y):
x = abs(x)
y = abs(y)
while x:
x, y = y % x, x
return y
インポート文も自動的に追加されます。 ファイル rational.py は次のようになります。
from collections import namedtuple
from util import gcd
class Rational(namedtuple('Rational', ['num', 'denom'])):
def __new__(cls, num, denom):
if denom == 0:
raise ValueError('Denominator cannot be null')
if denom < 0:
num, denom = -num, -denom
factor = gcd(num, denom)
return super().__new__(cls, num // factor, denom // factor)
def __str__(self):
return '{}/{}'.format(self.num, self.denom)
クラス Rational のさらなる変更
マジックメソッドの追加
次に、クラス Rational のオブジェクトに対する加算 / 減算演算用のマジックメソッドの宣言を追加しましょう。
from collections import namedtuple
from util import gcd
class Rational(namedtuple('Rational', ['num', 'denom'])):
def __new__(cls, num, denom):
if denom == 0:
raise ValueError('Denominator cannot be null')
factor = gcd(num, denom)
if denom < 0:
num, denom = -num, -denom
return super().__new__(cls, num // factor, denom // factor)
def __str__(self):
return '{}/{}'.format(self.num, self.denom)
def __add__(self, other):
if isinstance(other, int):
other = Rational(other, 1)
if isinstance(other, Rational):
new_num = self.num * other.denom + other.num * self.denom
new_denom = self.denom * other.denom
return Rational(new_num, new_denom)
return NotImplemented
def __neg__(self):
return Rational(-self.num, self.denom)
def __radd__(self, other):
return self + other
def __sub__(self, other):
return self + (-other)
def __rsub__(self, other):
return -self + other
メソッドの抽出とクイックフィックスの使用
次に、式 Rational(other, 1) を別のメソッドに抽出します。 これを行うには、前述の式にキャレットを置き、 Ctrl+Alt+M を押し、開いた ダイアログに新しいメソッド名 from_int を入力します。
最後に、メソッド from_int 宣言にキャレットを置き、 Alt+Enter を押し、候補リストから メソッドを static にする を選択し、 Enter を押します。
@staticmethod
def from_int(other):
return Rational(other, 1)
最後に、パラメーターの名前を other から number に変更しましょう。 これを行うには、パラメーターにキャレットを置き、 Shift+F6 を押します。
スーパークラスの抽出
次に、メソッド __radd__、 __sub__、 __rsub__ の実装をスーパークラスに移動します。 また、メソッド __neg__ と __add__ を抽象化します。
その方法は次のとおりです ... クラス Rational 宣言にキャレットを置き、コンテキストメニューで をポイントし、 を選択します。 次に、開いたダイアログでスーパークラスの名前 (ここでは AdditiveMixin) を指定し、スーパークラスに追加するメソッドを選択します。 メソッド __neg__ および __add__ の場合、列 抽象化する のチェックボックスを選択します。 詳細については、「スーパークラスの抽出 」を参照してください。
次のコードで終了します。
from abc import abstractmethod, ABCMeta
from collections import namedtuple
from util import gcd
class AdditiveMixin(metaclass=ABCMeta):
@abstractmethod
def __add__(self, other):
pass
@abstractmethod
def __neg__(self):
pass
def __radd__(self, other):
return self + other
def __sub__(self, other):
return self + (-other)
def __rsub__(self, other):
return -self + other
class Rational(namedtuple('Rational', ['num', 'denom']), AdditiveMixin):
def __new__(cls, num, denom):
if denom == 0:
raise ValueError('Denominator cannot be null')
factor = gcd(num, denom)
if denom < 0:
num, denom = -num, -denom
return super().__new__(cls, num // factor, denom // factor)
def __str__(self):
return '{}/{}'.format(self.num, self.denom)
def __add__(self, other):
if isinstance(other, int):
other = self.from_int(other)
if isinstance(other, Rational):
new_num = self.num * other.denom + other.num * self.denom
new_denom = self.denom * other.denom
return Rational(new_num, new_denom)
return NotImplemented
def from_int(self, number):
return Rational(number, 1)
def __neg__(self):
return Rational(-self.num, self.denom)
2026 年 6 月 1 日