You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过通用Pythonic方式获取类实例属性列表?优先支持预实例化检查

获取类实例属性列表的通用解决方案

需求

  • 优先实现无需实例化类就能获取实例属性列表(预实例化检查)
  • 若无法实现,寻求适用于通用类的最Pythonic实现方式

当前尝试及问题

可正常运行的基础实现

from typing import List
import inspect
import datetime as dt

class Apple:
    def __init__(self, color: str, size: int) -> None:
        self.log_time = dt.datetime.now()
        self.color = color
        self.size = size

def get_attributes(class_obj: object) -> List[str]:
    '''Returns instantiated class attributes.'''
    params = list(inspect.signature(class_obj).parameters.keys())
    kwargs = {param: None for param in params}
    instance = class_obj(**kwargs)
    attributes = list(vars(instance))
    return attributes

# 运行结果
# >>> ['log_time', 'color', 'size']

这个方法在__init__能接受None作为参数时可以正常工作,但遇到__init__中有参数运算的类就会报错:

触发错误的示例类

class Orange:
    def __init__(self, color: str, size: int) -> None:
        self.log_time = dt.datetime.now()
        self.color = color
        self.size = size
        self.another_attribute = size * 2

# 调用get_attributes(Orange)会触发如下错误:
# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# Cell In[63], line 1
# ----> 1 get_attributes(Orange)
# ...
# TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'

原因是__init__中存在size * 2的运算,传入None会触发类型错误,而用特定哑参数的方案不具备通用性。

解决方案

一、无需实例化的方案(局限性说明)

首先明确:完全不实例化就获取所有实例属性是不可能的,因为很多属性是在__init__甚至后续方法中动态生成的(比如示例中的log_time、another_attribute),这些属性只有在实例化过程中才会被绑定到实例上,类本身的定义里不会提前包含这些动态属性。

如果你的类是使用dataclasses或者attrs库定义的,可以直接从类的字段信息中获取属性列表,无需实例化:

from dataclasses import dataclass, fields

@dataclass
class AppleDataclass:
    color: str
    size: int
    log_time: dt.datetime = None

# 获取属性列表
print([field.name for field in fields(AppleDataclass)])
# >>> ['color', 'size', 'log_time']

但这种方案只适用于用特定库定义的类,对普通自定义类不通用。

二、通用实例化方案(Pythonic实现)

对于普通自定义类,必须实例化才能获取所有动态生成的属性,我们可以通过构造通用哑参数的策略来避免__init__中的运算错误:

from typing import List
import inspect
import datetime as dt
from unittest.mock import MagicMock

def get_attributes_generic(class_obj: type) -> List[str]:
    sig = inspect.signature(class_obj.__init__)
    kwargs = {}
    for param_name, param in sig.parameters.items():
        if param_name == 'self':
            continue
        # 优先根据类型注解生成合法哑值,否则用MagicMock模拟任意操作
        if param.annotation is not param.empty:
            try:
                # 尝试实例化类型(比如str()得到空串、int()得到0)
                kwargs[param_name] = param.annotation()
            except (TypeError, ValueError):
                # 无法实例化的类型(如泛型、抽象类)用MagicMock
                kwargs[param_name] = MagicMock()
        else:
            kwargs[param_name] = MagicMock()
    
    # 创建实例并获取所有属性
    instance = class_obj(**kwargs)
    return list(vars(instance))

# 测试Apple类
print(get_attributes_generic(Apple))
# >>> ['log_time', 'color', 'size']

# 测试Orange类
print(get_attributes_generic(Orange))
# >>> ['log_time', 'color', 'size', 'another_attribute']

方案说明

  1. 参数处理逻辑:
    • 自动跳过self参数
    • 利用类型注解生成合法哑值,避免None导致的运算错误
    • 对无法实例化的类型,用MagicMock模拟任意操作,确保__init__能正常执行
  2. 通用性:适配绝大多数自定义类,不管__init__中有没有参数运算,都能成功创建实例并获取所有属性
  3. 局限性:如果__init__依赖真实的外部资源(如数据库连接),MagicMock可能无法完全模拟,但这种场景需要结合业务需求调整实现逻辑

内容的提问来源于stack exchange,提问作者agftrading

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:35:20