| 22 | class ClassLoader: |
| 23 | @staticmethod |
| 24 | def load_class(file_path: str | Path, class_name: str) -> Type: |
| 25 | file_path = Path(file_path).resolve() |
| 26 | |
| 27 | if not file_path.exists(): |
| 28 | raise FileNotFoundError(file_path) |
| 29 | |
| 30 | # ⚠️ module_name 必须唯一,防止 sys.modules 冲突 |
| 31 | module_name = f"_dynamic_{file_path.stem}_{hash(file_path)}" |
| 32 | |
| 33 | spec = importlib.util.spec_from_file_location( |
| 34 | module_name, |
| 35 | str(file_path), |
| 36 | ) |
| 37 | if spec is None or spec.loader is None: |
| 38 | raise ImportError(file_path) |
| 39 | |
| 40 | module = importlib.util.module_from_spec(spec) |
| 41 | sys.modules[module_name] = module |
| 42 | spec.loader.exec_module(module) |
| 43 | |
| 44 | if not hasattr(module, class_name): |
| 45 | raise AttributeError( |
| 46 | f"Class '{class_name}' not found in {file_path}" |
| 47 | ) |
| 48 | |
| 49 | return getattr(module, class_name) |
| 50 | |
| 51 | |
| 52 | STRATEGY_PARAMS_ENV: Dict = {"verbose": False, "hold_num": 1, "leverage": 1.0} |