🐍
Python 3.7+ で typed dynamic property みたいなことしたいメモ
背景
class のインスタンス作ったときには property は作らない.
ユーザーが dynamic に(実行時に)つくったときに実行時型チェックしたい.
c = MyClass()
print(c.name) # NG. name はまだ存在しない
c.name = "" # str. OK
c.name = 3 # Error!
- 型付き property がほしい(property の名前と型は事前にわかっているようなのがある)
- None 状態はつくらず, property が無い状態を作りたい
- 型アノテーションで
Union[str, None]
とかめんどい. - また,
Union
などの typing ではisinstance
やtype
でのチェックはうまくいかない. - https://stackoverflow.com/questions/71525398/type-alias-with-union
- 一応対応策はあるが, Python のバージョンごとに違いややこしい.
- 型アノテーションで
- もしくは
None
には別の意味をもたせたい
のようなとき.
実装案
Python 3.8 だと TypedDict があり, より型の保証ができるとは思いますが,
まずは 3.7 で考えます.
↓の簡単な例であれば 3.5 あたりでも動くかもしれません.
class MyClass:
_builtin_props = { 'name': str, 'distance': int }
def __init__(self):
pass
def __setattr__(self, name, value):
if name in MyClass._builtin_props:
ty = self._builtin_props[name]
if not isinstance(value, ty):
if not isinstance(value, ty):
raise TypeError(
"Built-in property `{}` is type of `{}`, but got type `{}` for the value.".format(
name, ty.__name__, type(value).__name__))
self.__dict__[name] = value
__getattr__
, __getitem__
(myval["my:key"]
のように []
アクセス(literal では記述できない文字が含まれるときなど))は適宜必要に応じて実装して.
注意点
__getattr__
も定義していて, __getattr__
内で, 例えば↑で class variable(property) の _builtin_props
のスペルミスしてしまうなどで存在しない property にアクセスしようとすると, 無限に再帰で __getattr__
が呼ばれてしまい実行時エラーになるので気をつけましょう. 😢
TODO
-
numpy や torch を見るとより良い方法があるかもしれません(
dtype
で型チェックとかしていたはず)
Discussion