Coverage for src / c41811 / config / basic / _generate_operators.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-06 06:04 +0000

1# cython: language_level = 3 # noqa: ERA001 

2 

3 

4""" 

5辅助生成 

6 

7.. versionadded:: 0.2.0 

8""" 

9 

10from collections.abc import Callable 

11from functools import update_wrapper 

12from typing import Any 

13 

14import wrapt 

15 

16from .core import BasicSingleConfigData 

17from .factory import ConfigDataFactory 

18from .utils import check_read_only 

19 

20type Operator = Callable[[Any, Any], Any] 

21type InplaceOperator[S] = Callable[[S, Any], S] 

22 

23 

24def _generate_operators[S: Any]( 

25 operate_func: Operator, inplace_func: InplaceOperator[S] 

26) -> tuple[Operator, Operator, InplaceOperator[S]]: 

27 """ 

28 闭包绑定操作函数 

29 

30 :param operate_func: 操作函数 

31 :type operate_func: Operator 

32 :param inplace_func: 原地操作函数 

33 :type inplace_func: InplaceOperator[S] 

34 

35 :return: 绑定后的操作符实现 

36 :rtype: tuple[Operator, Operator, InplaceOperator[S]] 

37 """ 

38 

39 def forward_op(self: Any, other: Any) -> Any: 

40 return ConfigDataFactory(operate_func(self._data, other)) 

41 

42 def reverse_op(self: Any, other: Any) -> Any: 

43 return ConfigDataFactory(operate_func(other, self._data)) 

44 

45 # noinspection PyTypeHints 

46 def inplace_op(self: S, other: Any) -> S: 

47 self._data = inplace_func(self._data, other) 

48 return self 

49 

50 return forward_op, reverse_op, inplace_op 

51 

52 

53def generate[C](cls: type[C]) -> type[C]: 

54 """ 

55 为类生成操作符 

56 

57 需要使用 :py:deco:`operate` 装饰器标记要自动生成的操作符 

58 

59 :param cls: 目标类 

60 :type cls: type[C] 

61 

62 :return: 原样返回类 

63 :rtype: type[C] 

64 """ 

65 for name, func in dict(vars(cls)).items(): 

66 if not hasattr(func, "__generate_operators__"): 

67 continue 

68 operator_funcs = func.__generate_operators__ 

69 delattr(func, "__generate_operators__") 

70 

71 # 动态创建函数 

72 forward_op, reverse_op, inplace_op = _generate_operators( 

73 operator_funcs["operate_func"], operator_funcs["inplace_func"] 

74 ) 

75 

76 # 设置函数标识符 

77 i_name = f"__i{name[2:-2]}__" 

78 r_name = f"__r{name[2:-2]}__" 

79 forward_op.__qualname__ = func.__qualname__ 

80 reverse_op.__qualname__ = f"{cls.__qualname__}.{r_name}" 

81 inplace_op.__qualname__ = f"{cls.__qualname__}.{i_name}" 

82 

83 # 应用装饰器 

84 @wrapt.decorator 

85 def wrapper(wrapped: Callable[..., Any], _instance: C, args: tuple[Any, ...], kwargs: dict[str, Any]) -> Any: 

86 if isinstance(args[0], BasicSingleConfigData): 

87 args = (args[0].data, *args[1:]) 

88 return wrapped(*args, **kwargs) 

89 

90 setattr(cls, name, update_wrapper(wrapper(forward_op), forward_op)) 

91 setattr(cls, r_name, reverse_op) 

92 setattr(cls, i_name, update_wrapper(wrapper(check_read_only(inplace_op)), inplace_op)) 

93 

94 return cls 

95 

96 

97def operate[F: Operator]( 

98 operate_func: Operator, 

99 inplace_func: InplaceOperator[Any], 

100) -> Callable[[F], F]: 

101 """ 

102 将方法标记为需要生成标记符 

103 

104 :param operate_func: 操作函数 

105 :type operate_func: Operator 

106 :param inplace_func: 原地操作函数 

107 :type inplace_func: InplaceOperator[Any] 

108 

109 :return: 装饰器 

110 :rtype: Callable[[F], F] 

111 """ 

112 

113 def decorator(func: F) -> F: 

114 func.__generate_operators__ = { # type: ignore[attr-defined] 

115 "operate_func": operate_func, 

116 "inplace_func": inplace_func, 

117 } 

118 return func 

119 

120 return decorator 

121 

122 

123__all__ = ( 

124 "generate", 

125 "operate", 

126)