pythonで動的キャストを安全に実現させるには
解決したいこと
pythonで、文字列にて指定された型へとオブジェクトを型変換する方法を探しています。
例えば
cast(int, 3.14)
が3
になるようにするには、単にcast = lambda tipe, obj: tipe(obj)
でいいわけですが、
cast("int", 3.14)
で同じことをする方法を探しています。
できればeval
を使わない安全なものがいいです。
自分で試したこと
動的な型変換を行う方法はなかなか見つかりませんでした。
そこで、文字列を、その意味通りのtypeオブジェクトに変換する関数を書いてみました。
get_type_from_str
import re
def get_type_from_str(string):
err = type("InjectionAttackBrocked",(Exception,),{})("実行可能コードの恐れのある文字列をブロックしました")
if type(string) is not str:
raise err
try:
if re.search(r"[0-9a-zA-z_]+",string).group() != string:
raise err
except Exception:
raise err
try:
if type(eval(string)) is type:
return eval(string)
except Exception:
return "None"
print(get_type_from_str("int")) # expecting <class 'int'>
print(get_type_from_str("list"))# expecting <class 'list'>
cast = lambda tipe_str,obj: get_type_from_str(tipe_str)(obj)
print(cast("int", 3.14)) # expecting 3 (because of casting to int)
print(get_type_from_str("get_type_from_str = False")) # expecting InjectionAttackBrocked being raised
実行結果
<class 'int'>
<class 'list'>
3
---------------------------------------------------------------------------
InjectionAttackBrocked Traceback (most recent call last)
<ipython-input-102-3049d4234b65> in <module>
19 cast = lambda tipe_str,obj: get_type_from_str(tipe_str)(obj)
20 print(cast("int", 3.14)) # expecting 3
---> 21 print(get_type_from_str("get_type_from_str = False"))
22
23
<ipython-input-102-3049d4234b65> in get_type_from_str(string)
8 raise err
9 except Exception:
---> 10 raise err
11 try:
12 if type(eval(string)) is type:
<ipython-input-102-3049d4234b65> in get_type_from_str(string)
6 try:
7 if re.search(r"[0-9a-zA-z_]+",string).group() != string:
----> 8 raise err
9 except Exception:
10 raise err
InjectionAttackBrocked: 実行可能コードの恐れのある文字列をブロックしました
発生している問題・エラー
この関数は正直安全とは言えないと思います。
引数無しの関数が実行可能だからです。
(eval
は「式の評価」しかせず、「文の実行」にはexec
が必要なことが有名ですが、関数呼び出しは式なので、eval
から呼び出し可能であり、副作用も存在し得ます。)
また、もう少し簡単に動的キャストが実現できるのなら、その方が望ましいと考えています。
0 likes