-
functools.singledispatch 로 typeclass 흉내 내기python/응용 2024. 1. 24. 18:10
- https://docs.python.org/3/library/functools.html#functools.singledispatch
- https://news.ycombinator.com/item?id=22682219
- functools.singledispatch 를 이용해 typeclass 처럼 만들어 보자
코드
import dataclasses import functools import math from typing import Any @dataclasses.dataclass class Circle: radius: float @dataclasses.dataclass class Rectangle: width: float height: float @functools.singledispatch def area(shape: Any) -> float: raise TypeError(f"{type(shape)} is not allowed") @area.register def _(shape: Circle) -> float: return math.pi * shape.radius ** 2 @area.register def _(shape: Rectangle) -> float: return shape.width * shape.height result = area(Circle(radius=2)) print(result)
singledispatch 한계
https://dev.to/wemake-services/typeclasses-in-python-3ma6
- mypy 로 타입 체크가 안됨
- 특정 타입에 대해 구현이 안되어 있을 경우 실행해 보기 전에 체크할 수 없다..
- Protocol 지원 안됨
생각해 볼 문제
Overloading
python 에서 아래처럼 구현이 허용되면 좋겠지만, 기본적으로 type 으로 function 을 구분할 수 없으므로 불가능하다.
def area(shape: Circle) -> float: return math.pi * shape.radius ** 2 def area(shape: Rectangle) -> float: return shape.width * shape.height
하지만 https://github.com/mrocklin/multipledispatch/ 를 이용하면 비슷하게 코딩할 수 있어 보이기도 하다.
(사용해 보니 약간 불안정해 보임 - Circle 과 Retangle member 를 혼용?)
from multipledispatch import dispatch @dispatch(Circle) def area(shape) -> float: return math.pi * shape.radius ** 2 @dispatch(Rectangle) def area(shape) -> float: return shape.width * shape.height
typeclass 흉내를 냈지만
singledispatch 를 사용한 코드는, 결국 아래랑 다를게 없어 보인다.
def area(shape: Any) -> float: if isinstance(shape, Circle): return math.pi * shape.radius ** 2 elif isinstance(shape, Rectangle): return shape.width * shape.height else: raise TypeError(f"{type(shape)} is not allowed")
참고
- 아래처럼 singledispatch 에서 Union type 을 사용할 수 있는데, python 3.11 이상 부터 가능한 듯
@area.register def _(shape: Circle | Rectangle) -> float: ...
- class method 대상으로는 singledispatch 대신에 singledispatchmethod 를 사용한다.
- typeclass vs overloading: https://stackoverflow.com/questions/50373097/scala-type-class-pattern-vs-pattern-matching-or-overloading
'python > 응용' 카테고리의 다른 글
python MixIn (0) 2024.01.31 Coroutine yield 의 동작 이해 (0) 2023.12.13 yield 활용 2 (0) 2023.11.15 yield 활용 1 (0) 2023.11.15 Decorators with parameters (0) 2023.10.17