marble log

Webエンジニアの技術ブログです

PythonでJavaのOptionalクラスを実装する

Pythonで型ヒントが使えるようになってから、mypyなどの型の静的解析の活用もあいまってPythonでプロダクションレベルの開発がしやすくなった。 ただ、JavaのOptionalクラスのような、Noneの扱う便利クラス/メソッドは言語レベルでは提供されていないため、自前かライブラリを利用する必要がある。

型ヒントを活用して、JavaのOptionalクラスの一部の機能を実現するOptionクラスを実装した。Optionalは型ヒントですでに使用されているため、クラス名はOptionとした。

from typing import Callable, Generic, Optional, TypeVar

T = TypeVar("T")
U = TypeVar("U")

"""JavaのOptionalクラスを実現するクラス
"""


class Option(Generic[T]):
    """コンストラクタ

    JavaのOptionalクラスが持つof、ofNullableメソッドの機能をコンストラクタで担う。
    Javaのofメソッドに相当する、None非許容のコンストラクタは作らない。

    :param value: 値
    :return: インスタンス
    """

    def __init__(self, value: Optional[T]):
        self.__value = value

    """値を返すメソッド。JavaのOptionalクラスと異なり、値がNoneでも例外は投げない。

    :return: 値
    """

    def get(self) -> Optional[T]:
        return self.__value

    """値が存在する場合はTrue、そうでない場合はFalseを返す。

    :return: 値が存在する場合はTrue、そうでない場合はFalse
    """

    def is_present(self) -> bool:
        return self.__value is not None

    """値が存在する場合は値を返し、そうでない場合はotherを返す。

    :param other: Noneの場合に返す値
    :return: Optionの値かother
    """

    def or_else(self, other: T) -> T:
        return self.__value or other

    """マッピング関数をその値に適用した結果をOptionで返す。valueがNoneの場合は空のOptionを返す。

    :param mapper: マッピング関数
    :return: マッピング関数を適用した結果
    """

    def map(self, mapper: Callable[[T], U]) -> "Option[U]":
        if self.__value is None:
            return Option(None)
        return Option(mapper(self.__value))

    """値が存在し、その値が与えられた述語に一致する場合は、値を記述するOptionを返し、それ以外の場合は空のOptionを返す。

    :param predicate: フィルター関数
    :return: フィルターを適用した結果
    """

    def filter(self, predicate: Callable[[T], bool]) -> "Option[T]":
        if self.__value is None:
            return Option(None)
        return self if predicate(self.__value) else Option(None)