0

0

python中怎么获取一个对象的所有属性?

冰火之心

冰火之心

发布时间:2025-09-13 11:35:01

|

1149人浏览过

|

来源于php中文网

原创

要获取Python对象的所有属性,常用方法是dir()和__dict__;dir()返回对象所有可访问的属性和方法(包括继承和特殊方法),适用于探索对象的完整接口;而__dict__仅包含实例自身的数据属性,不包含方法和类属性,适合查看实例状态。两者区别在于:dir()提供全面的成员列表,__dict__则聚焦实例的命名空间。若需过滤特殊属性或区分数据与方法,可结合getattr()和callable()进行判断;在继承场景中,dir()遵循MRO包含基类成员,__dict__仅显示实例自身属性。实际应用中,根据需求选择合适方法:dir()用于概览,__dict__用于序列化或调试实例数据。

python中怎么获取一个对象的所有属性?

在Python中,要获取一个对象的所有属性,最常用的方法是使用内置函数

dir()
或直接访问对象的
__dict__
属性。这两者各有侧重,
dir()
更偏向于探索对象所有可访问的成员,包括方法和继承的属性,而
__dict__
则主要关注实例自身的、非方法的数据属性。具体用哪个,得看你“所有属性”的定义是什么。

解决方案

当我们谈论获取Python对象的所有属性时,通常是在尝试理解一个对象能做什么,或者它内部存储了什么数据。这里有几种核心的策略,每种都有其适用场景和需要注意的地方。

首先,最直观且全面的工具是内置的

dir()
函数。当你对一个对象调用
dir()
时,它会返回一个包含该对象所有有效属性(包括方法、数据属性以及从其类和基类继承的属性)名称的列表。这对于快速概览一个对象的能力非常有用。例如:

class MyClass:
    class_attr = "I'm a class attribute"

    def __init__(self, name, value):
        self.name = name
        self.value = value

    def greet(self):
        return f"Hello, {self.name}!"

obj = MyClass("Alice", 100)
print(dir(obj))
# 结果会包含 'name', 'value', 'greet', 'class_attr' 以及大量内置的特殊方法(如__init__, __str__等)

然而,如果你只对对象实例自身定义的那些数据属性感兴趣,而不是那些方法或者从类、父类继承下来的东西,那么访问对象的

__dict__
属性会更直接。
__dict__
是一个字典,存储了实例的命名空间,键是属性名,值是属性值。并非所有对象都有
__dict__
(例如,某些内置类型就没有),但对于我们自己定义的类实例,它通常是可用的。

立即学习Python免费学习笔记(深入)”;

print(obj.__dict__)
# 结果通常是 {'name': 'Alice', 'value': 100}
# 注意:class_attr 和 greet 方法不会出现在这里,因为它们是类属性/方法,而不是实例属性。

还有一个相关的内置函数

vars()
,它在没有参数时返回当前作用域
__dict__
,当传入一个对象时,如果该对象有
__dict__
属性,
vars(obj)
会返回
obj.__dict__
。所以,
vars(obj)
基本上是
obj.__dict__
的一个便捷别名,但它在处理没有
__dict__
的对象时会抛出
TypeError

print(vars(obj))
# 结果同 obj.__dict__: {'name': 'Alice', 'value': 100}

在实际开发中,我发现

dir()
适合探索未知对象,而
__dict__
更适合在需要序列化对象状态或进行运行时修改实例数据时使用。

Python中dir()和dict有什么区别

这个问题问得好,这是理解Python对象模型时一个非常核心的知识点。我个人在初学Python时也曾为此困惑,因为它们看起来都像是在列举属性,但结果却大相径庭。

最根本的区别在于它们的目的和范围

dir()
函数的设计初衷是提供一个“目录”或“索引”,列出对象所有可访问的成员。这意味着它不仅会包含对象实例自己定义的属性(比如
obj.name
),还会包括:

  1. 方法: 无论是实例方法、类方法还是静态方法,只要能通过对象访问,
    dir()
    都会列出。
  2. 继承的属性和方法: 对象从其类以及所有父类继承的属性和方法,
    dir()
    也会一并呈现。
  3. 特殊方法(dunder methods): 那些以双下划线开头和结尾的特殊方法,如
    __init__
    ,
    __str__
    ,
    __add__
    等,它们定义了对象的行为,
    dir()
    也会显示。

所以,

dir()
给我们的是一个综合性的视图,告诉你这个对象“能做什么”和“拥有什么公共接口”。它背后的机制比较复杂,涉及到对象的
__dir__
方法、类的
__dict__
和父类的
__dict__
等。

__dict__
属性则是一个字典,它仅仅存储了对象实例自身的、非方法的数据属性。也就是说:

  1. 仅限实例属性: 只有那些直接通过
    self.attribute = value
    形式在实例上创建或修改的属性才会出现在
    __dict__
    中。
  2. 不包含方法: 方法是存储在类定义中的,而不是每个实例的
    __dict__
    里。
  3. 不包含类属性: 如果类定义了一个
    class_attr
    ,除非你在实例上显式地给
    obj.class_attr
    赋值(这会创建一个同名的实例属性并“遮蔽”类属性),否则它也不会出现在
    __dict__
    中。
  4. 不包含继承的属性: 除非这些继承的属性在实例上被重新赋值。

举个例子可能更清晰:

class Parent:
    parent_attr = "From Parent"
    def parent_method(self): pass

class Child(Parent):
    child_attr = "From Child"
    def __init__(self, instance_attr):
        self.instance_attr = instance_attr
    def child_method(self): pass

c = Child("hello")

print("dir(c) 结果示例 (部分):")
for attr in dir(c):
    if not attr.startswith('__'): # 过滤掉特殊方法,让结果更清晰
        print(attr)
# 可能会输出:child_attr, instance_attr, parent_attr, child_method, parent_method 等

print("\nc.__dict__ 结果:")
print(c.__dict__)
# 输出: {'instance_attr': 'hello'}

从这个例子可以看出,

dir(c)
包含了
child_attr
(类属性)、
parent_attr
(继承的类属性)、
child_method
(实例方法) 和
parent_method
(继承的方法),以及
instance_attr
(实例属性)。而
c.__dict__
则只有
instance_attr
。这就像
dir()
是一个图书馆的总目录,列出了所有书籍和房间;而
__dict__
只是你个人书桌上放的书,仅此而已。

如何只获取对象的用户自定义属性,排除内置方法和特殊属性?

在很多实际场景中,我们可能并不想看到

dir()
返回的那些冗长的内置特殊方法(比如
__init__
,
__str__
,
__add__
等),或者那些仅仅是方法而不是数据属性的成员。我们更关心的是那些我们自己定义在类或实例上的“有意义”的属性。要实现这一点,我们需要对
dir()
的结果进行一些过滤,或者结合
__dict__
getattr()
进行判断。

方法一:过滤

dir()
的结果

这是最直接也最常用的方式。通常,用户自定义的属性和方法不会以双下划线开头和结尾(

__attr__
形式)。所以,我们可以遍历
dir(obj)
的结果,并排除掉那些符合“dunder”命名模式的项。

倍塔塞司
倍塔塞司

AI职业规划、AI职业测评、定制测评、AI工具等多样化职业类AI服务。

下载
class MyObject:
    class_data = 10
    def __init__(self, name):
        self.name = name
        self.age = 30
    def say_hello(self):
        return f"Hello, {self.name}"

obj = MyObject("Bob")

user_defined_attrs = []
for attr_name in dir(obj):
    if not attr_name.startswith('__') and not attr_name.endswith('__'):
        user_defined_attrs.append(attr_name)

print("用户自定义属性 (不含dunder):", user_defined_attrs)
# 结果可能类似:['age', 'class_data', 'name', 'say_hello']

这个列表里依然会包含方法,如果你只想获取数据属性,还需要进一步判断。

方法二:结合

getattr()
判断是否可调用

如果你想进一步区分数据属性和方法,可以使用

getattr()
获取属性本身,然后用
callable()
函数来判断它是否是一个可调用的对象(即方法)。

class MyObject:
    class_data = 10
    def __init__(self, name):
        self.name = name
        self.age = 30
    def say_hello(self):
        return f"Hello, {self.name}"

obj = MyObject("Bob")

data_attrs = []
methods = []

for attr_name in dir(obj):
    if not attr_name.startswith('__') and not attr_name.endswith('__'):
        attr_value = getattr(obj, attr_name)
        if callable(attr_value):
            methods.append(attr_name)
        else:
            data_attrs.append(attr_name)

print("用户自定义数据属性:", data_attrs)
# 结果可能类似:['age', 'class_data', 'name']
print("用户自定义方法:", methods)
# 结果可能类似:['say_hello']

这种方法相对健壮,能清晰地将数据和行为分开。

方法三:利用

__dict__
(主要用于实例数据)

如果你只关心实例上直接定义的数据属性,

__dict__
是最直接的选择。它天然地排除了类属性、继承属性和方法。

class MyObject:
    class_data = 10
    def __init__(self, name):
        self.name = name
        self.age = 30
    def say_hello(self):
        return f"Hello, {self.name}"

obj = MyObject("Bob")

instance_data_attrs = obj.__dict__.keys()
print("实例数据属性:", list(instance_data_attrs))
# 结果:['name', 'age']

请注意,这种方法不会包含

class_data
,因为它是一个类属性。如果你需要同时获取类属性和实例属性,那么方法二会更合适。选择哪种方法,完全取决于你对“用户自定义属性”的具体定义和需求。我个人在做对象序列化或者调试时,经常会用
obj.__dict__
来快速查看实例的内部状态。

在继承和多态场景下,如何正确获取对象的属性?

继承和多态是面向对象编程的核心,它们使得代码更具复用性和灵活性。但在这种复杂的关系中,理解对象属性的来源和查找顺序变得尤为重要。正确获取属性,意味着你需要知道一个属性是来自实例本身、它的类、还是它的某个父类。

首先,

dir()
在继承场景下表现得非常“智能”。当你对一个子类实例调用
dir()
时,它会按照Python的方法解析顺序(Method Resolution Order, MRO)来查找所有可访问的属性和方法。这意味着它会自然地包含从所有基类继承下来的公共成员。

class Grandparent:
    grand_attr = "Grand"
    def grand_method(self): pass

class Parent(Grandparent):
    parent_attr = "Parent"
    def parent_method(self): pass

class Child(Parent):
    child_attr = "Child"
    def __init__(self, name):
        self.name = name
    def child_method(self): pass

c = Child("Charlie")

print("dir(c) 在继承场景下的结果 (部分):")
for attr in dir(c):
    if not attr.startswith('__') and not attr.endswith('__'):
        print(attr)
# 输出会包含:child_attr, parent_attr, grand_attr, name, child_method, parent_method, grand_method

可以看到,

dir(c)
自动收集了
Grandparent
Parent
Child
类以及实例
c
上的所有非特殊属性。这对于快速了解一个复杂继承体系下对象的全貌非常方便。

然而,

__dict__
在继承场景下则显得“保守”得多。它只会显示那些直接在当前实例上设置的属性。这意味着,从父类继承的类属性或方法,如果没有在子类实例上被显式地重新赋值,就不会出现在子类实例的
__dict__
中。

print("\nc.__dict__ 在继承场景下的结果:")
print(c.__dict__)
# 输出: {'name': 'Charlie'}

这里的

c.__dict__
只包含了
name
,因为它是
Child
类的
__init__
方法中通过
self.name
设置的实例属性。
child_attr
parent_attr
grand_attr
等类属性以及所有方法都不会出现,因为它们是类级别的,不是实例级别的。

如果你需要明确知道一个属性是来自实例、类还是父类,或者想更细致地控制,

inspect
模块会提供更强大的内省能力,比如
inspect.getmembers()
。它允许你指定一个谓词(predicate)来过滤成员类型。

import inspect

class Grandparent:
    grand_attr = "Grand"
    def grand_method(self): pass

class Parent(Grandparent):
    parent_attr = "Parent"
    def parent_method(self): pass

class Child(Parent):
    child_attr = "Child"
    def __init__(self, name):
        self.name = name
    def child_method(self): pass

c = Child("David")

print("\n使用 inspect.getmembers 获取所有数据属性:")
# inspect.isdatadescriptor 检查是否是数据描述符(包括普通属性)
# inspect.ismethod 检查是否是方法
# inspect.isfunction 检查是否是函数 (对于类中的方法,它会是method)

# 获取所有非特殊的数据属性 (包括类属性和实例属性)
all_data_attrs = [name for name, value in inspect.getmembers(c, lambda member: not inspect.ismethod(member) and not inspect.isfunction(member) and not name.startswith('__'))]
print(all_data_attrs)
# 结果可能类似:['child_attr', 'grand_attr', 'name', 'parent_attr']

# 获取所有方法
all_methods = [name for name, value in inspect.getmembers(c, inspect.ismethod)]
print(all_methods)
# 结果可能类似:['child_method', 'grand_method', 'parent_method']

inspect.getmembers()
结合不同的谓词,能让你在继承和多态的复杂结构中,更精确地筛选出你想要的属性类型。它会遍历MRO,所以能看到所有可访问的成员。

理解

dir()
__dict__
在继承链上的行为差异,对于调试、反射编程和元编程都至关重要。
dir()
给你一个高层次的“能见度”,而
__dict__
则揭示了实例最核心的、独有的状态。
inspect
模块则提供了更精细的控制,让你能像外科医生一样,精确地解剖对象的内部结构。在实践中,我通常会先用
dir()
快速摸清对象的大致轮廓,然后根据需要深入到
__dict__
inspect
模块来获取更具体的信息。

相关文章

python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

56

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

52

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1179

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

215

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2089

2025.12.29

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

54

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.7万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号