0

0

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

冰火之心

冰火之心

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

|

1129人浏览过

|

来源于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”命名模式的项。

Bardeen AI
Bardeen 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开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

775

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

684

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

768

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

719

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1445

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

571

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

751

2023.08.11

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

58

2026.01.23

热门下载

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

精品课程

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

共4课时 | 21万人学习

Django 教程
Django 教程

共28课时 | 3.5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

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

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