サイトアイコン ITC Media

【わかりやすい】Pythonの構造体とは?コード付きで徹底解説

(最終更新月:2023年6月)

✔こんな方におすすめです

「Pythonで構造体を使いたいけど、どうすればいいのか分からない」

「Python構造体の定義方法を知りたい」

「Python構造体の具体的な実装例が見たい」

✔この記事を通してお伝えする情報

当記事では、Python構造体の基本概念から、実践的な活用方法まで、具体的な例を交えて丁寧に解説しています。

ぜひ最後までお読みいただき、Python構造体の活用にお役立てください。

構造体の基本

こちらでは、「構造体の基本」についてお伝えしていきます。

構造体の理解はデータを効率的に管理するために非常に重要です。

C言語での構造体

構造体は、異なるデータ型の変数をひとつにまとめられる機能のこと。

主にはC言語で一般的な用語です。

例えば、学生の名前(文字列型)、学生番号(整数型)、成績(浮動小数点型)などを一つの構造体として定義することが可能になります。

Pythonと構造体の関係

PythonにはC言語のような直接的な構造体の概念は存在しませんが、似たような機能を実現できます。

クラスを使用する方法

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("John", 30)
print(person.name)  # Output: "John"
print(person.age)  # Output: 30

辞書を使用する方法

person = {"name": "John", "age": 30}
print(person["name"])  # Output: "John"
print(person["age"])  # Output: 30

タプルを使用する方法

person = ("John", 30)
print(person[0])  # Output: "John"
print(person[1])  # Output: 30

名前付きタプル(namedtuple)を使用する方法

from collections import namedtuple

Person = namedtuple("Person", ["name", "age"])
person = Person("John", 30)
print(person.name)  # Output: "John"
print(person.age)  # Output: 30

データクラス(dataclass)を使用する方法

from dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int

person = Person("John", 30)
print(person.name)  # Output: "John"
print(person.age)  # Output: 30

これらの方法を使用することで、C言語の構造体に似た機能を実現できます。

それぞれの方法には異なる特徴と利点を理解して、状況に応じて最適な方法を選択しましょう。

Pythonでの構造体のメリット

次に、「Pythonでの構造体のメリット」について説明します。

コードの効率化や可読性向上の方法を理解してください。

データ管理の効率化

Pythonでの構造体的な手法を利用することで、データをより効率的に管理できます。

異なる型のデータをまとめて扱えて、データ構造の設計や操作が容易になるからです

例えば、以下のような学生のデータを管理する場合を考えてみましょう。

class Student:
    def __init__(self, name, age, grade):
        self.name = name
        self.age = age
        self.grade = grade

students = [
    Student("John", 18, "A"),
    Student("Emma", 17, "B"),
    Student("Michael", 19, "A"),
]

上記の例では、学生の名前、年齢、成績をひとつの構造体で管理しています。

これにより、各学生の情報を一元管理しやすくなります。

コードの可読性向上

Pythonでは、それぞれのデータに名前をつけて管理できるため、コードの可読性も向上します。

以下のような座標のデータを扱う場合を考えてみましょう。

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

def calculate_distance(point1, point2):
    # 二点間の距離を計算するロジック
    pass

point1 = Point(2, 3)
point2 = Point(5, 7)
distance = calculate_distance(point1, point2)

上記の例では、座標データを表すための構造体であるPointを定義しています。

コードの可読性が向上し、座標データを直感的に操作できます。

構造体を使用することで、関連するデータをまとめ、それを利用するコードをより明確かつ直感的に表現できるのです。

代替手法の紹介

Pythonでの構造体の代替手法として、「クラス」「namedtuple」「dataclass」の3つを紹介します。

それぞれの特徴と適した利用シーンを理解しましょう。

クラスによる代替

Pythonで、最も汎用性が高い構造体の代替手法はクラスを使用する方法です。

クラスはメソッド(関数)とプロパティ(データ)を持つことができ、独自のデータ型を作成するために使用されます。

例えば、以下のように学生の情報を持つクラスを作成することが可能です。

class Student:
    def __init__(self, name, id, score):
        self.name = name
        self.id = id
        self.score = score

このようにクラスを使用すれば、さまざまなデータ型のデータでもまとめて管理できます。

クラスの中にメソッドを定義して、データ操作もクラス内部で完結可能です。

namedtupleによる代替

namedtupleは、タプルと同様に不変のデータを持つことができる代替手法です。

通常のタプルと異なり、各要素に名前をつけてアクセスできます。

namedtupleは構造体に近い形でデータを保持することができ、以下のように定義します。

from collections import namedtuple

Student = namedtuple('Student', ['name', 'id', 'score'])

namedtupleは不変性を必要とする場合や、データの名前付きアクセスが必要な場合に適しています。

メモリ効率も良く、大量のデータを扱う場合にも有用です。

dataclassによる代替

Python 3.7から追加されたdataclassも、構造体のようにデータをまとめて保持するための手法です。

データクラスは、クラス定義のためのデコレータで、フィールドの定義を簡潔に記述できます。

from dataclasses import dataclass

@dataclass
class Student:
    name: str
    id: int
    score: float

dataclassは、クラスに比べて定義が簡単であり、データを中心にしたクラスを作成する際に便利です。

また、デフォルトの比較操作(等価性、順序)や文字列化(__repr__)を自動的に提供します。

注意点とポイント

こちらでは、構造体を扱う上での注意するポイントをご紹介します。

代替手法の比較

Pythonで構造体を模倣する各手法には、それぞれ特徴と適用するべきシチュエーションがあります。

クラスは最も柔軟性があり、複雑なデータ構造を表現できますが、それだけに定義が少々煩雑になります。

一方、namedtupleとdataclassは定義が簡潔であり、特にdataclassはデータを中心としたクラスを容易に定義可能です。

しかし、これらは不変(immutable)であるため、データの変更が頻繁に行われる場合には向いていません。

# クラスのインスタンスは変更可能
s1 = Student('Alice', 1, 90.0)
s1.score = 95.0  # OK

# namedtupleとdataclassのインスタンスは変更不可
s2 = Student_nt('Bob', 2, 85.0)
s2.score = 90.0  # エラー

s3 = Student_dc('Charlie', 3, 80.0)
s3.score = 85.0  # エラー

値渡しと参照渡しの違い

Pythonでは、オブジェクトはすべて参照によって渡されます。

オブジェクト自体が関数に渡されるのではなく、そのオブジェクトへの参照(つまり、オブジェクトのメモリ上の位置を示すポインタ)が渡されることを意味します。

したがって、関数内でオブジェクトを変更すると、その変更は関数の外側からも見えます。

def update_score(student, new_score):
    student.score = new_score  # 外側のオブジェクトが変更される

s1 = Student('Alice', 1, 90.0)
update_score(s1, 95.0)
print(s1.score)  # 95.0

しかし、namedtupleとdataclassのインスタンスは不変であるため、このような変更はできません。

新しい値でインスタンスを作り直す必要があります。

クラスの扱いにおける注意事項

Pythonのクラスには、いくつかの注意点があります。

Pythonでは、新しいインスタンスが作成された直後に自動的に呼び出されます。

初期化したい変数がある場合、このメソッド内で定義することが一般的です。

class Student:
    def __init__(self, name, id, score):
        self.name = name
        self.id = id
        self.score = score

さらに、Pythonのクラスはデータ属性とメソッドを同時に持つことができますが、データ属性を直接操作するというのは一般的に良くないとされています。

データ操作専用のメソッド(ゲッターやセッターと呼ばれる)を定義しましょう。

これは、クラスが自身のデータを「カプセル化」する、というオブジェクト指向の原則に基づいています。

まとめ

当記事では、Pythonでの構造体とその代替手法について学習してきました。

それぞれの手法がどのような状況で最適かを理解することで、コードの品質と効率性が向上します。

Pythonのスキルを磨くには、実際にコードを書いてみることが最も重要です。

とくに当記事で紹介したようなデータ構造やオブジェクト指向の概念は、実際に手を動かして学ばなかえれば、身につきにくいといえるでしょう。

Python習得の旅は長いですが、その道のりは非常に充実したものとなるでしょう。

モバイルバージョンを終了