Python:Eval
Python eval
함수에 대한 설명
Annotation 누실 문제
예컨데 eval
실행 직전과 직후 site-packages 목록이 바뀐다면 eval
타이밍에 Type Annotation 정보가 포함된 __annotations__
내용이 유실되어, type
이 str
으로 바뀌어 들어올 수 있다. 이 문제를 해결하기 위해 다음과 같은 함수를 만들어 eval
직후 local_variables
와 global_variables
를 갱신한다.
# -*- coding: utf-8 -*-
from inspect import ismethod
from typing import Any, Dict, Optional
ATTRIBUTE_FUNC = "__func__"
ATTRIBUTE_ANNOTATIONS = "__annotations__"
ATTRIBUTE_WRAPPED = "__wrapped__"
def eval_annotations(
obj: Any,
global_variables: Optional[Dict[str, Any]] = None,
local_variables: Optional[Dict[str, Any]] = None,
) -> None:
"""
If the annotation of the variable executed by the `eval` function
is passed in the form of `str`, it is converted to the type.
"""
if ismethod(obj):
assert hasattr(obj, ATTRIBUTE_FUNC)
eval_annotations(
getattr(obj, ATTRIBUTE_FUNC),
global_variables,
local_variables,
)
return
if not hasattr(obj, ATTRIBUTE_ANNOTATIONS):
return
if global_variables is None:
global_variables = globals()
if local_variables is None:
local_variables = locals()
annotations = getattr(obj, ATTRIBUTE_ANNOTATIONS)
assert isinstance(annotations, dict)
update_annotations: Dict[str, Any] = dict()
for key, annotation in annotations.items():
if isinstance(annotation, str):
type_origin = eval(annotation, global_variables, local_variables)
if type_origin is not None:
eval_annotations(type_origin, global_variables, local_variables)
update_annotations[key] = type_origin
else:
update_annotations[key] = annotation
else:
update_annotations[key] = annotation
setattr(obj, ATTRIBUTE_ANNOTATIONS, update_annotations)
# It can be a wrapped object.
# Where to use: `inspect.signature` -> ... -> `inspect.unwrap`
if hasattr(obj, ATTRIBUTE_WRAPPED):
eval_annotations(
getattr(obj, ATTRIBUTE_WRAPPED),
global_variables,
local_variables,
)