新しいプリミティブ型を作成する

Beginner

This tutorial is from open-source community. Access the source code

はじめに

この実験では、Python で新しいプリミティブ型を作成し、それに必要なメソッドを実装する方法を学びます。また、Python のオブジェクトプロトコルについても理解を深めます。ほとんどの Python プログラムでは、intfloatstr などの組み込みプリミティブ型を使ってデータを表現します。しかし、Python では、標準ライブラリの decimalfractions モジュールのように、カスタム型を作成することもできます。

この実験では、MutInt(Mutable Integer、可変整数)という新しいプリミティブ型を作成します。Python の不変整数とは異なり、MutInt は作成後に変更することができます。この演習では、Python で完全に機能するプリミティブ型を作成するために必要な基本原則を紹介します。

これは Guided Lab です。学習と実践を支援するためのステップバイステップの指示を提供します。各ステップを完了し、実践的な経験を積むために、指示に注意深く従ってください。過去のデータによると、この 初級 レベルの実験の完了率は 90%です。学習者から 97% の好評価を得ています。

基本的な MutInt クラスの作成

まずは、可変整数型(Mutable Integer)の基本的なクラスを作成しましょう。プログラミングにおいて、クラスはオブジェクトを作成するためのブループリントのようなものです。このステップでは、新しいプリミティブ型の基礎を構築します。プリミティブ型とは、プログラミング言語が提供する基本的なデータ型で、ここでは独自のカスタム型を作成します。

  1. WebIDE を開き、/home/labex/project ディレクトリに移動します。WebIDE は、コードを記述、編集、実行できる統合開発環境です。このディレクトリに移動することで、すべてのファイルが一箇所に整理され、適切に相互作用できるようになります。

  2. セットアップステップで作成された mutint.py ファイルを開きます。このファイルは、MutInt クラスの定義を記述する場所になります。

  3. 次のコードを追加して、基本的な MutInt クラスを定義します。

## mutint.py

class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

__slots__ 属性は、このクラスが持つことができる属性を定義するために使用されます。属性は、クラスのオブジェクトに属する変数のようなものです。__slots__ を使用することで、Python に属性を格納するためのよりメモリ効率の良い方法を使用するよう指示します。この場合、MutInt クラスは value という単一の属性のみを持つことになります。つまり、MutInt クラスの各オブジェクトは、整数値という 1 つのデータのみを保持できます。

__init__ メソッドは、クラスのコンストラクタです。コンストラクタは、クラスのオブジェクトが作成されるときに呼び出される特別なメソッドです。これは value パラメータを受け取り、それをインスタンスの value 属性に格納します。インスタンスとは、クラスのブループリントから作成された個々のオブジェクトのことです。

クラスを使用する Python スクリプトを作成して、テストしてみましょう。

  1. 同じディレクトリに test_mutint.py という新しいファイルを作成します。
## test_mutint.py

from mutint import MutInt

## Create a MutInt object
a = MutInt(3)
print(f"Created MutInt with value: {a.value}")

## Modify the value (demonstrating mutability)
a.value = 42
print(f"Modified value to: {a.value}")

## Try adding (this will fail)
try:
    result = a + 10
    print(f"Result of a + 10: {result}")
except TypeError as e:
    print(f"Error when adding: {e}")

このテストスクリプトでは、まず mutint.py ファイルから MutInt クラスをインポートします。次に、初期値 3 で MutInt クラスのオブジェクトを作成します。初期値を出力し、その後 42 に変更して新しい値を出力します。最後に、MutInt オブジェクトに 10 を足そうとしますが、このクラスはまだ加算演算をサポートしていないため、エラーが発生します。

  1. ターミナルで次のコマンドを実行して、テストスクリプトを実行します。
python3 /home/labex/project/test_mutint.py

ターミナルは、システムやコードと対話するための様々なコマンドを実行できるコマンドラインインターフェイスです。このコマンドを実行すると、test_mutint.py スクリプトが実行されます。

次のような出力が表示されるはずです。

Created MutInt with value: 3
Modified value to: 42
Error when adding: unsupported operand type(s) for +: 'MutInt' and 'int'

MutInt クラスは、値を正常に格納して更新することができます。しかし、いくつかの制限があります。

  • 印刷するときに見栄えが良くない
  • 加算などの数学的演算をサポートしていない
  • 比較演算をサポートしていない
  • 型変換をサポートしていない

次のステップでは、これらの制限を 1 つずつ解消して、MutInt クラスをより本格的なプリミティブ型のように動作させます。

文字列表現の改善

Python で MutInt オブジェクトを印刷すると、<__main__.MutInt object at 0x...> のような出力が表示されます。この出力は、MutInt オブジェクトの実際の値を示していないため、あまり役に立ちません。オブジェクトが表すものを理解しやすくするために、文字列表現用の特殊メソッドを実装します。

  1. WebIDE で mutint.py を開き、次のコードで更新します。
## mutint.py

class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

    def __str__(self):
        """Return a string representation for printing."""
        return str(self.value)

    def __repr__(self):
        """Return a developer-friendly string representation."""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """Support string formatting with format specifications."""
        return format(self.value, fmt)

MutInt クラスに 3 つの重要なメソッドを追加しました。

  • __str__(): このメソッドは、オブジェクトに str() 関数を使用するとき、またはオブジェクトを直接印刷するときに呼び出されます。人間が読みやすい文字列を返す必要があります。
  • __repr__(): このメソッドは、オブジェクトの「公式」な文字列表現を提供します。主にデバッグに使用され、理想的には eval() 関数に渡すとオブジェクトを再作成できる文字列を返す必要があります。
  • __format__(): このメソッドにより、MutInt オブジェクトで Python の文字列フォーマットシステムを使用できます。パディングや数値フォーマットなどのフォーマット指定を使用できます。
  1. これらの新しいメソッドをテストするために、test_string_repr.py という新しいテストファイルを作成します。
## test_string_repr.py

from mutint import MutInt

## Create a MutInt object
a = MutInt(3)

## Test string representation
print(f"str(a): {str(a)}")
print(f"repr(a): {repr(a)}")

## Test direct printing
print(f"Print a: {a}")

## Test string formatting
print(f"Formatted with padding: '{a:*^10}'")
print(f"Formatted as decimal: '{a:d}'")

## Test mutability
a.value = 42
print(f"After changing value, repr(a): {repr(a)}")

このテストファイルでは、まず MutInt クラスをインポートします。次に、値が 3MutInt オブジェクトを作成します。str()repr() 関数を使用して __str__()__repr__() メソッドをテストします。また、直接印刷、文字列フォーマット、および MutInt オブジェクトの可変性もテストします。

  1. テストスクリプトを実行します。
python3 /home/labex/project/test_string_repr.py

このコマンドを実行すると、Python は test_string_repr.py スクリプトを実行します。次のような出力が表示されるはずです。

str(a): 3
repr(a): MutInt(3)
Print a: 3
Formatted with padding: '****3*****'
Formatted as decimal: '3'
After changing value, repr(a): MutInt(42)

これで、MutInt オブジェクトが見やすく表示されるようになりました。文字列表現には基になる値が表示され、通常の整数と同じように文字列フォーマットを使用できます。

__str__()__repr__() の違いは、__str__() は人間が読みやすい出力を生成することを目的としているのに対し、__repr__() は理想的には eval() に渡すとオブジェクトを再作成できる文字列を生成する必要があるということです。このため、__repr__() メソッドにクラス名を含めました。

__format__() メソッドにより、オブジェクトが Python のフォーマットシステムと連携できるようになり、パディングや数値フォーマットなどのフォーマット指定を使用できます。

数学的演算の追加

現在、私たちの MutInt クラスは加算などの数学的演算をサポートしていません。Python では、カスタムクラスにこのような演算を有効にするには、特殊メソッドを実装する必要があります。これらの特殊メソッドは、二重アンダースコアで囲まれているため、「マジックメソッド」または「ダンダーメソッド」とも呼ばれます。算術演算に関連する特殊メソッドを実装して、加算機能を追加しましょう。

  1. WebIDE で mutint.py を開き、次のコードで更新します。
## mutint.py

class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

    def __str__(self):
        """Return a string representation for printing."""
        return str(self.value)

    def __repr__(self):
        """Return a developer-friendly string representation."""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """Support string formatting with format specifications."""
        return format(self.value, fmt)

    def __add__(self, other):
        """Handle addition: self + other."""
        if isinstance(other, MutInt):
            return MutInt(self.value + other.value)
        elif isinstance(other, int):
            return MutInt(self.value + other)
        else:
            return NotImplemented

    def __radd__(self, other):
        """Handle reversed addition: other + self."""
        ## For commutative operations like +, we can reuse __add__
        return self.__add__(other)

    def __iadd__(self, other):
        """Handle in-place addition: self += other."""
        if isinstance(other, MutInt):
            self.value += other.value
            return self
        elif isinstance(other, int):
            self.value += other
            return self
        else:
            return NotImplemented

MutInt クラスに 3 つの新しいメソッドを追加しました。

  • __add__(): このメソッドは、+ 演算子が左側に MutInt オブジェクトを持つ場合に呼び出されます。このメソッド内では、まず other オペランドが MutInt のインスタンスまたは int であるかを確認します。もしそうであれば、加算を実行し、結果を持つ新しい MutInt オブジェクトを返します。other オペランドがそれ以外の場合は、NotImplemented を返します。これは、Python に他のメソッドを試すか、TypeError を発生させるよう指示します。
  • __radd__(): このメソッドは、+ 演算子が右側に MutInt オブジェクトを持つ場合に呼び出されます。加算は可換演算(つまり、a + bb + a と同じ)であるため、__add__ メソッドを再利用できます。
  • __iadd__(): このメソッドは、+= 演算子が MutInt オブジェクトに使用された場合に呼び出されます。新しいオブジェクトを作成する代わりに、既存の MutInt オブジェクトを変更して返します。
  1. これらの新しいメソッドをテストするために、test_math_ops.py という新しいテストファイルを作成します。
## test_math_ops.py

from mutint import MutInt

## Create MutInt objects
a = MutInt(3)
b = MutInt(5)

## Test regular addition
c = a + b
print(f"a + b = {c}")

## Test addition with int
d = a + 10
print(f"a + 10 = {d}")

## Test reversed addition
e = 7 + a
print(f"7 + a = {e}")

## Test in-place addition
print(f"Before a += 5: a = {a}")
a += 5
print(f"After a += 5: a = {a}")

## Test in-place addition with reference sharing
f = a  ## f and a point to the same object
print(f"Before a += 10: a = {a}, f = {f}")
a += 10
print(f"After a += 10: a = {a}, f = {f}")

## Test unsupported operation
try:
    result = a + 3.5  ## Adding a float is not supported
    print(f"a + 3.5 = {result}")
except TypeError as e:
    print(f"Error when adding float: {e}")

このテストファイルでは、まず MutInt クラスをインポートします。次に、いくつかの MutInt オブジェクトを作成し、さまざまな種類の加算演算を実行します。また、インプレース加算と、サポートされていない演算(浮動小数点数の加算)を試みた場合もテストします。

  1. テストスクリプトを実行します。
python3 /home/labex/project/test_math_ops.py

次のような出力が表示されるはずです。

a + b = MutInt(8)
a + 10 = MutInt(13)
7 + a = MutInt(10)
Before a += 5: a = MutInt(3)
After a += 5: a = MutInt(8)
Before a += 10: a = MutInt(8), f = MutInt(8)
After a += 10: a = MutInt(18), f = MutInt(18)
Error when adding float: unsupported operand type(s) for +: 'MutInt' and 'float'

これで、MutInt クラスは基本的な加算演算をサポートするようになりました。+= を使用したときに、af の両方が更新されたことに注意してください。これは、a += 10 が新しいオブジェクトを作成するのではなく、既存のオブジェクトを変更したことを示しています。

この可変オブジェクトの動作は、Python の組み込み可変型(リストなど)と似ています。例えば:

a = [1, 2, 3]
b = a
a += [4, 5]  ## Both a and b are updated

対照的に、タプルなどの不変型の場合、+= は新しいオブジェクトを作成します。

c = (1, 2, 3)
d = c
c += (4, 5)  ## c is a new object, d still points to the old one

比較演算の実装

現在、私たちの MutInt オブジェクトは、互いに比較することも、通常の整数と比較することもできません。Python では、==<<=>>= などの比較演算は、オブジェクトを操作する際に非常に便利です。これらの演算により、異なるオブジェクト間の関係を判断でき、ソート、フィルタリング、条件文などの多くのプログラミングシナリオで重要です。そこで、比較演算の特殊メソッドを実装して、MutInt クラスに比較機能を追加しましょう。

  1. WebIDE で mutint.py を開き、次のコードで更新します。
## mutint.py

from functools import total_ordering

@total_ordering
class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

    def __str__(self):
        """Return a string representation for printing."""
        return str(self.value)

    def __repr__(self):
        """Return a developer-friendly string representation."""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """Support string formatting with format specifications."""
        return format(self.value, fmt)

    def __add__(self, other):
        """Handle addition: self + other."""
        if isinstance(other, MutInt):
            return MutInt(self.value + other.value)
        elif isinstance(other, int):
            return MutInt(self.value + other)
        else:
            return NotImplemented

    def __radd__(self, other):
        """Handle reversed addition: other + self."""
        return self.__add__(other)

    def __iadd__(self, other):
        """Handle in-place addition: self += other."""
        if isinstance(other, MutInt):
            self.value += other.value
            return self
        elif isinstance(other, int):
            self.value += other
            return self
        else:
            return NotImplemented

    def __eq__(self, other):
        """Handle equality comparison: self == other."""
        if isinstance(other, MutInt):
            return self.value == other.value
        elif isinstance(other, int):
            return self.value == other
        else:
            return NotImplemented

    def __lt__(self, other):
        """Handle less-than comparison: self < other."""
        if isinstance(other, MutInt):
            return self.value < other.value
        elif isinstance(other, int):
            return self.value < other
        else:
            return NotImplemented

いくつかの重要な改良を加えました。

  1. functools モジュールから @total_ordering デコレータをインポートして使用します。@total_ordering デコレータは Python の強力なツールです。クラスの比較メソッドを実装する際に、多くの時間と労力を節約できます。6 つの比較メソッド(__eq____ne____lt____le____gt____ge__)を手動で定義する代わりに、__eq__ ともう 1 つの比較メソッド(この場合は __lt__)を定義するだけで済みます。デコレータは自動的に残りの 4 つの比較メソッドを生成します。

  2. 等価比較(==)を処理する __eq__() メソッドを追加します。このメソッドは、2 つの MutInt オブジェクト、または MutInt オブジェクトと整数が同じ値を持っているかをチェックするために使用されます。

  3. 小なり比較(<)を処理する __lt__() メソッドを追加します。このメソッドは、1 つの MutInt オブジェクト、または MutInt オブジェクトと整数を比較した場合に、値が小さいかどうかを判断するために使用されます。

  4. これらの新しいメソッドをテストするために、test_comparisons.py という新しいテストファイルを作成します。

## test_comparisons.py

from mutint import MutInt

## Create MutInt objects
a = MutInt(3)
b = MutInt(3)
c = MutInt(5)

## Test equality
print(f"a == b: {a == b}")  ## Should be True (same value)
print(f"a == c: {a == c}")  ## Should be False (different values)
print(f"a == 3: {a == 3}")  ## Should be True (comparing with int)
print(f"a == 5: {a == 5}")  ## Should be False (different values)

## Test less than
print(f"a < c: {a < c}")    ## Should be True (3 < 5)
print(f"c < a: {c < a}")    ## Should be False (5 is not < 3)
print(f"a < 4: {a < 4}")    ## Should be True (3 < 4)

## Test other comparisons (provided by @total_ordering)
print(f"a <= b: {a <= b}")  ## Should be True (3 <= 3)
print(f"a > c: {a > c}")    ## Should be False (3 is not > 5)
print(f"c >= a: {c >= a}")  ## Should be True (5 >= 3)

## Test with a different type
print(f"a == '3': {a == '3'}")  ## Should be False (different types)

このテストファイルでは、いくつかの MutInt オブジェクトを作成し、それらに対してさまざまな比較演算を実行します。また、MutInt オブジェクトを通常の整数や異なる型(この場合は文字列)と比較します。これらのテストを実行することで、比較メソッドが期待通りに動作することを確認できます。

  1. テストスクリプトを実行します。
python3 /home/labex/project/test_comparisons.py

次のような出力が表示されるはずです。

a == b: True
a == c: False
a == 3: True
a == 5: False
a < c: True
c < a: False
a < 4: True
a <= b: True
a > c: False
c >= a: True
a == '3': False

これで、MutInt クラスはすべての比較演算をサポートするようになりました。

@total_ordering デコレータは、6 つの比較メソッドを手動で実装する必要がないため、特に便利です。__eq____lt__ を提供するだけで、Python は他の 4 つの比較メソッドを自動的に導出できます。

カスタムクラスを実装する際には、通常、同じ型のオブジェクトと組み込み型の両方で動作するようにするのが良い習慣です。そのため、比較メソッドは MutInt オブジェクトと通常の整数の両方を処理します。これにより、MutInt クラスはさまざまなプログラミングシナリオでより柔軟に使用できます。

型変換の追加

現在の MutInt クラスは、加算と比較の操作をサポートしています。しかし、Python の組み込み変換関数である int()float() とは連携しません。これらの変換関数は Python では非常に便利です。たとえば、さまざまな計算や操作のために値を整数または浮動小数点数に変換したい場合、これらの関数に頼ることになります。そこで、MutInt クラスにこれらの関数と連携する機能を追加しましょう。

  1. WebIDE で mutint.py を開き、以下のコードで更新します。
## mutint.py

from functools import total_ordering

@total_ordering
class MutInt:
    """
    作成後に値を変更できる可変整数クラス。
    """
    __slots__ = ['value']

    def __init__(self, value):
        """整数値で初期化します。"""
        self.value = value

    def __str__(self):
        """印刷用の文字列表現を返します。"""
        return str(self.value)

    def __repr__(self):
        """開発者向けの文字列表現を返します。"""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """書式指定による文字列の書式設定をサポートします。"""
        return format(self.value, fmt)

    def __add__(self, other):
        """加算を処理します:self + other。"""
        if isinstance(other, MutInt):
            return MutInt(self.value + other.value)
        elif isinstance(other, int):
            return MutInt(self.value + other)
        else:
            return NotImplemented

    def __radd__(self, other):
        """逆加算を処理します:other + self。"""
        return self.__add__(other)

    def __iadd__(self, other):
        """インプレース加算を処理します:self += other。"""
        if isinstance(other, MutInt):
            self.value += other.value
            return self
        elif isinstance(other, int):
            self.value += other
            return self
        else:
            return NotImplemented

    def __eq__(self, other):
        """等価比較を処理します:self == other。"""
        if isinstance(other, MutInt):
            return self.value == other.value
        elif isinstance(other, int):
            return self.value == other
        else:
            return NotImplemented

    def __lt__(self, other):
        """より小さい比較を処理します:self < other。"""
        if isinstance(other, MutInt):
            return self.value < other.value
        elif isinstance(other, int):
            return self.value < other
        else:
            return NotImplemented

    def __int__(self):
        """int に変換します。"""
        return self.value

    def __float__(self):
        """float に変換します。"""
        return float(self.value)

    __index__ = __int__  ## 配列のインデックス操作や、インデックスを必要とするその他の操作をサポートします

    def __lshift__(self, other):
        """左シフトを処理します:self << other。"""
        if isinstance(other, MutInt):
            return MutInt(self.value << other.value)
        elif isinstance(other, int):
            return MutInt(self.value << other)
        else:
            return NotImplemented

    def __rlshift__(self, other):
        """逆左シフトを処理します:other << self。"""
        if isinstance(other, int):
            return MutInt(other << self.value)
        else:
            return NotImplemented

MutInt クラスに 3 つの新しいメソッドを追加しました。

  1. __int__(): このメソッドは、MutInt クラスのオブジェクトに対して int() 関数を使用すると呼び出されます。たとえば、MutInt オブジェクト a があり、int(a) と記述すると、Python は a オブジェクトの __int__() メソッドを呼び出します。
  2. __float__(): 同様に、このメソッドは、MutInt オブジェクトに対して float() 関数を使用すると呼び出されます。
  3. __index__(): このメソッドは、特に整数インデックスを必要とする操作に使用されます。たとえば、インデックスを使用してリスト内の要素にアクセスしたり、ビット長操作を実行したりする場合、Python は整数インデックスを必要とします。
  4. __lshift__(): このメソッドは、MutInt オブジェクトが << 演算子の左側にある場合に、左シフト演算を処理します。
  5. __rlshift__(): このメソッドは、MutInt オブジェクトが << 演算子の右側にある場合に、左シフト演算を処理します。

__index__ メソッドは、リストのインデックス操作、スライス、ビット長操作など、整数インデックスを必要とする操作にとって非常に重要です。この簡単な実装では、MutInt オブジェクトの値は整数インデックスとして直接使用できるため、__int__ と同じになるように設定しました。

__lshift__ および __rlshift__ メソッドは、ビット単位の左シフト演算をサポートするために不可欠です。これらにより、MutInt オブジェクトはビット単位の演算に参加できるようになります。これは、整数のような型によくある要件です。

  1. これらの新しいメソッドをテストするために、test_conversions.py という名前の新しいテストファイルを作成します。
## test_conversions.py

from mutint import MutInt

## MutInt オブジェクトを作成します
a = MutInt(3)

## 変換をテストします
print(f"int(a): {int(a)}")
print(f"float(a): {float(a)}")

## インデックスとして使用してテストします
names = ['Dave', 'Guido', 'Paula', 'Thomas', 'Lewis']
print(f"names[a]: {names[a]}")

## ビット演算で使用してテストします (__index__ が必要です)
print(f"1 << a: {1 << a}")  ## 3 だけ左にシフトします

## hex/oct/bin 関数を使用してテストします (__index__ が必要です)
print(f"hex(a): {hex(a)}")
print(f"oct(a): {oct(a)}")
print(f"bin(a): {bin(a)}")

## 変更して再度テストします
a.value = 4
print(f"\n値を 4 に変更した後:")
print(f"int(a): {int(a)}")
print(f"names[a]: {names[a]}")
  1. テストスクリプトを実行します。
python3 /home/labex/project/test_conversions.py

次のような出力が表示されるはずです。

int(a): 3
float(a): 3.0
names[a]: Thomas
1 << a: 8
hex(a): 0x3
oct(a): 0o3
bin(a): 0b11

値を 4 に変更した後:
int(a): 4
names[a]: Lewis

これで、MutInt クラスは標準の Python 型に変換でき、整数インデックスを必要とする操作で使用できます。

__index__ メソッドは特に重要です。これは、リストのインデックス操作、ビット単位の演算、hex()oct()bin() などのさまざまな関数など、整数インデックスが必要な状況でオブジェクトを使用できるようにするために Python で導入されました。

これらの追加により、MutInt クラスはかなり完全なプリミティブ型になりました。通常の整数が使用されるほとんどのコンテキストで使用でき、可変であるという利点が追加されています。

完全な MutInt の実装

以下は、追加したすべての機能を備えた完全な MutInt の実装です。

## mutint.py

from functools import total_ordering

@total_ordering
class MutInt:
    """
    作成後に値を変更できる可変整数クラス。
    """
    __slots__ = ['value']

    def __init__(self, value):
        """整数値で初期化します。"""
        self.value = value

    def __str__(self):
        """印刷用の文字列表現を返します。"""
        return str(self.value)

    def __repr__(self):
        """開発者向けの文字列表現を返します。"""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """書式指定による文字列の書式設定をサポートします。"""
        return format(self.value, fmt)

    def __add__(self, other):
        """加算を処理します:self + other。"""
        if isinstance(other, MutInt):
            return MutInt(self.value + other.value)
        elif isinstance(other, int):
            return MutInt(self.value + other)
        else:
            return NotImplemented

    def __radd__(self, other):
        """逆加算を処理します:other + self。"""
        return self.__add__(other)

    def __iadd__(self, other):
        """インプレース加算を処理します:self += other。"""
        if isinstance(other, MutInt):
            self.value += other.value
            return self
        elif isinstance(other, int):
            self.value += other
            return self
        else:
            return NotImplemented

    def __eq__(self, other):
        """等価比較を処理します:self == other。"""
        if isinstance(other, MutInt):
            return self.value == other.value
        elif isinstance(other, int):
            return self.value == other
        else:
            return NotImplemented

    def __lt__(self, other):
        """より小さい比較を処理します:self < other。"""
        if isinstance(other, MutInt):
            return self.value < other.value
        elif isinstance(other, int):
            return self.value < other
        else:
            return NotImplemented

    def __int__(self):
        """int に変換します。"""
        return self.value

    def __float__(self):
        """float に変換します。"""
        return float(self.value)

    __index__ = __int__  ## 配列のインデックス操作や、インデックスを必要とするその他の操作をサポートします

    def __lshift__(self, other):
        """左シフトを処理します:self << other。"""
        if isinstance(other, MutInt):
            return MutInt(self.value << other.value)
        elif isinstance(other, int):
            return MutInt(self.value << other)
        else:
            return NotImplemented

    def __rlshift__(self, other):
        """逆左シフトを処理します:other << self。"""
        if isinstance(other, int):
            return MutInt(other << self.value)
        else:
            return NotImplemented

この実装は、Python で新しいプリミティブ型を作成する際の重要な側面を網羅しています。さらに完全にするには、減算、乗算、除算などの他の操作のためのメソッドを追加で実装できます。

まとめ

この実験では、Python で独自のプリミティブ型を作成する方法を学びました。具体的には、組み込み型に似た可変整数クラスの作成、オブジェクト表示用の特殊メソッドの実装、数学的および比較演算のサポートの追加、さまざまな Python コンテキストでの型変換の有効化を習得しました。

これらの概念は、Python のオブジェクトモデルを理解するために不可欠であり、組み込み操作とうまく統合されるカスタム型を作成するために使用できます。さらなる知識を深めるために、より多くの数学的演算を実装したり、他の組み込み関数のサポートを追加したり、カスタムコレクションなどの複雑な型を探索したりすることを検討してください。Python のカスタム型は、特定のニーズに合わせて言語を拡張する強力なツールです。