2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C#開発者がPythonのEnumを使ってみた ― IntEnum・Flag・StrEnumの違いと使い分け

Last updated at Posted at 2025-08-24

はじめに

image.png

C#を過去に使っていたのですが、最近Pythonで実装することになり、列挙型(Enum)を使おうとしたところ、「あれ?C#と全然違う...」となった経験があります。

C#では当たり前にできていたことが、Pythonだと別のやり方が必要だったり、逆にPythonの方が便利な機能があったり。同じ「Enum」という名前なのに、なぜこんなに違うのか?

この記事では、C#開発者の視点でPythonのEnum事情をまとめてみました。API開発やDB設計で「どっちを使うべき?」と迷った時の参考にしてください。

C#のEnumをおさらい

まずは馴染みのあるC#のEnumから。基本的な特徴を確認しておきましょう。

基本的な使い方

public enum Color : int
{
    Red = 1,
    Green = 2,
    Blue = 3
}

var c = Color.Red;
Console.WriteLine(c);        // "Red"
Console.WriteLine((int)c);   // 1

ビットフラグ

[Flags]
public enum Permission
{
    Read = 1,
    Write = 2,
    Execute = 4
}

var perm = Permission.Read | Permission.Write;
Console.WriteLine(perm.HasFlag(Permission.Write));  // True

C#のEnumは:

  • 既定でintベース(bytelong等も指定可能)
  • [Flags]属性でビット演算ができる
  • JSONシリアライズは数値が既定(設定で文字列化も可能)
  • 値との直接比較が簡単

PythonのEnumを使ってみた

基本的なEnum

from enum import Enum, auto

class Color(Enum):
    RED = auto()
    GREEN = auto()
    BLUE = auto()

c = Color.RED
print(c.name)   # "RED"
print(c.value)  # 1

最初に驚いたのはauto()の存在。C#だと値を明示的に指定するのが普通ですが、Pythonでは自動採番できるんですね。デフォルトでは1から順番に採番されますが、内部的には generate_next_value で決まるため、カスタマイズも可能です。

image.png

IntEnum:整数との比較ができるEnum

from enum import IntEnum

class Status(IntEnum):
    PENDING = 1
    PROCESSING = 2
    COMPLETED = 3

# これができる!
print(Status.PENDING == 1)  # True
print(Status.PENDING < Status.COMPLETED)  # True

通常のEnumだとStatus.PENDING == 1Falseになってしまいます。C#に慣れていると、この違いでハマりがちです。

Flag:ビット演算対応のEnum

from enum import Flag, auto

class Permission(Flag):
    READ = auto()
    WRITE = auto()
    EXECUTE = auto()

perm = Permission.READ | Permission.WRITE
print(Permission.WRITE in perm)  # True

C#の[Flags]と同じようなことができます。inで含まれているかチェックできるのは直感的ですね。
整数との比較も行いたい場合は IntFlag を使うとC#の [Flags] により近い挙動になります。

image.png

StrEnum:文字列特化のEnum(Python 3.11+)

from enum import StrEnum

class OrderStatus(StrEnum):
    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"

status = OrderStatus.PENDING
print(status)           # "pending"
print(status.value)     # "pending"
print(str(status))      # "pending"

これはC#にはない機能!文字列として直接使える。

image.png

実際に使ってみて感じた違い

Web APIでの使用例

C#の場合:

// JsonStringEnumConverterの設定が必要
public enum ApiStatus
{
    Success,
    Error
}

// レスポンス例: {"status": "Success"}

Pythonの場合:

from fastapi import FastAPI
from enum import StrEnum

class ApiStatus(StrEnum):
    SUCCESS = "success"
    ERROR = "error"

@app.get("/api/status")
def get_status():
    return {"status": ApiStatus.SUCCESS}  # 自動で文字列化

PythonのStrEnumは設定不要で文字列として扱えるので、API開発がとても楽でした。

データベース保存での違い

C#(Entity Framework):

// 設定が必要
modelBuilder.Entity<Order>()
    .Property(e => e.Status)
    .HasConversion<string>();

Python(SQLAlchemy):

from sqlalchemy import Enum as SqlEnum

class Order(Base):
    # 文字列として保存したい場合
    status = Column(SqlEnum(OrderStatus), nullable=False)
    
    # または.valueを使う
    status_value = Column(String, nullable=False)

SqlEnum を使うとデータベースにチェック制約が生成されます。単に文字列を保存したい場合は Column(String) + .value を使う方がシンプルです。

ハマったポイント:比較の違い

from enum import Enum

class Color(Enum):
    RED = 1
    BLUE = 2

# C#的な発想でやりがちな間違い
color_from_db = 1
if color_from_db == Color.RED:  # False!
    print("赤です")

# 正しい比較方法
if Color(color_from_db) == Color.RED:  # True
    print("赤です")
# または
if color_from_db == Color.RED.value:  # True
    print("赤です")

これは最初かなりハマりました。C#だと当たり前にできる比較が、Pythonでは明示的な変換が必要です。
ただし、color_from_db に存在しない値を渡すと ValueError が発生するので注意してください。

どのEnumを選ぶべき?使い分けガイド

実際に使ってみた結果、こんな使い分けをしています:

用途 推奨 理由
API レスポンス StrEnum JSON で文字列として直接出力される
データベース保存(文字列) StrEnum 可読性が高い
データベース保存(数値) IntEnum パフォーマンス重視、既存システム連携
ビット演算が必要 Flag / IntFlag 権限管理など
型安全重視 Enum 意図しない比較を防げる

パフォーマンスで気をつけたこと

ループ処理でEnum比較を多用する場合は注意が必要です:

# 避けたい例(毎回Enum変換)
for item in large_list:
    if item.status == OrderStatus.PENDING:
        process_item(item)

# 改善例(事前に値を取得)
pending_value = OrderStatus.PENDING.value
for item in large_list:
    if item.status == pending_value:
        process_item(item)

C# vs Python:機能比較表

機能 C# Python
基盤型 int固定(他の整数型指定可) 任意型(int, str, tuple...)
自動採番 なし auto()
ビット演算 [Flags] Flag / IntFlag
文字列Enum 標準では不可 StrEnum (3.11+)
値との直接比較 可能 IntEnumのみ可能
JSON シリアライズ 設定で文字列化 .valueまたはStrEnum使用
パターンマッチ switch match文 (3.10+)

まとめ

image.png

C#とPythonのEnum、同じ名前でも結構違いました:

  • C#:強い型安全性、数値ベース、シンプル
  • Python:柔軟性、文字列対応、豊富なバリエーション

特にPythonのStrEnumはAPI開発で本当に便利。C#でも同じような機能が欲しくなります。

一方で、型安全性を重視するならPythonでも基本のEnumを使って、明示的な変換を心がける方が良い場面もあります。

どちらの言語でも「数値で保存するか、文字列で保存するか」をチーム内で統一しておくことが大切ですね。

参考リンク

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?