獲取類中所有聲明或類型化的參數(shù)

獲取類中所有聲明或類型化的參數(shù)

本文旨在提供一種使用 python 反射機制獲取類及其父類中所有聲明或類型化的參數(shù)的方法。通過結(jié)合 inspect.get_annotations 和類的 __mro__ 屬性,我們可以提取包括父類在內(nèi)的所有類型注解,并將其組織成一個易于使用的字典。本文提供詳細的代碼示例和解釋,幫助讀者理解和應用這一技術。

使用 inspect.get_annotations 和 __mro__ 獲取參數(shù)類型信息

Python 的 inspect 模塊提供了強大的反射功能,其中 inspect.get_annotations 函數(shù)可以獲取指定對象的類型注解。類的 __mro__ 屬性則包含了類的繼承關系,即方法解析順序(Method Resolution Order)。結(jié)合這兩個工具,我們可以遍歷類的繼承鏈,提取所有父類的類型注解。

以下是一個示例代碼:

import inspect from typing import Any, Optional, Dict  class Parent:     parent_param: str     parent_default: Optional[str] = None      @classmethod     def find_params_meta(cls) -> Dict[str, Any]:         params_meta = {}         for c in reversed(cls.__mro__):             if hasattr(c, '__annotations__'):                 for k, v in inspect.get_annotations(c).items():                     if k not in params_meta: # 避免子類覆蓋父類同名參數(shù)的類型信息                         params_meta[k] = {"types": [v]}                         if hasattr(cls, k) and getattr(cls, k) != inspect._empty:                             params_meta[k]["default"] = getattr(cls, k)         return params_meta   class Child(Parent):     child_param: str     _params_meta: Optional[Dict[str, Any]] = None      def __init__(self, parent_param: str, child_param: str):         self._params_meta = self.find_params_meta()         self.child_param = child_param         self.parent_param = parent_param      def __getattr__(self, name):         # 模擬未初始化的屬性訪問         raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")  # 實例化對象并打印結(jié)果 child_instance = Child("parent param", "child param") print(child_instance._params_meta)  # 斷言 expected_result = {     "parent_param": {"types": [str]},     "parent_default": {"types": [str, type(None)], "default": None},     "child_param": {"types": [str]}, }  assert child_instance._params_meta == expected_result

代碼解釋:

  1. Parent 類和 Child 類: 定義了父類 Parent 和子類 Child,包含類型注解的類屬性。
  2. find_params_meta 方法: 這是一個類方法,用于獲取類及其父類的類型注解。
  3. cls.__mro__: __mro__ 屬性返回一個包含類及其所有父類的元組,按照方法解析順序排列。 使用 reversed 反轉(zhuǎn)這個順序,確保子類的類型信息優(yōu)先。
  4. inspect.get_annotations(c): 獲取每個類 c 的類型注解,返回一個字典。
  5. 類型信息合并: 遍歷父類鏈時,將父類的類型信息合并到 params_meta 中。如果子類定義了與父類同名的參數(shù),則子類的類型信息優(yōu)先。
  6. 默認值獲取: 檢查類屬性是否有默認值,如果有則添加到結(jié)果字典中。
  7. __getattr__ 方法: 為了模擬問題描述中“未實例化屬性”的場景,重寫了 __getattr__ 方法,當訪問不存在的屬性時拋出 AttributeError。

運行結(jié)果:

{'parent_param': {'types': [<class 'str'>]}, 'parent_default': {'types': [<class 'str'>, <class 'NoneType'>], 'default': None}, 'child_param': {'types': [<class 'str'>]}

注意事項

  • 類型覆蓋: 在繼承關系中,如果子類重新定義了父類的屬性,并且類型注解不同,則子類的類型注解會覆蓋父類的類型注解。
  • 性能: 使用反射可能會影響性能,特別是在頻繁調(diào)用的場景中。 可以考慮緩存結(jié)果以提高性能。
  • 兼容性: inspect.get_annotations 是 Python 3.9 引入的,如果需要兼容更早的版本,可以使用 typing.get_type_hints。

總結(jié)

通過結(jié)合 inspect.get_annotations 和 __mro__ 屬性,我們可以方便地獲取類及其父類的類型注解。這對于實現(xiàn)一些通用的工具函數(shù),例如自動生成 API 文檔、參數(shù)校驗等非常有用。 在實際應用中,需要注意類型覆蓋、性能和兼容性等問題。

? 版權聲明
THE END
喜歡就支持一下吧
點贊10 分享