首页 / Python3 入门教程 / 获取对象信息与类属性

Python3 入门教程

获取对象信息与类属性

本教程共 70 篇 · 第 34 篇 · 更新于 2026-07-22 · 约 5 分钟阅读

PythonPython3 入门教程内省类属性isinstance__slots__

34. 获取对象信息与类属性

本节目标:学会用 type()isinstance()dir()hasattr() 等工具检查对象,彻底分清实例属性和类属性的区别。

代码写多了,经常需要回答这些问题:这个对象是什么类型?它有哪些方法?某个属性存在吗?Python 提供了一系列内建函数,让你能在运行时「 introspect(内省)」对象。

type():查看对象类型

print(type(123))       # <class 'int'>
print(type('hello'))   # <class 'str'>
print(type([]))        # <class 'list'>

对于自定义类,同样适用:

class Dog:
    pass

d = Dog()
print(type(d))  # <class '__main__.Dog'>

type() 返回的是对象的精确类型,不考虑继承关系。

isinstance():考虑继承链

上一章提过,isinstancetype 更宽松:

class Animal: pass
class Dog(Animal): pass

d = Dog()
print(isinstance(d, Dog))      # True
print(isinstance(d, Animal))   # True
print(type(d) == Animal)       # False

isinstance 还可以同时检查多个类型:

print(isinstance(123, (int, str)))   # True
print(isinstance([], (list, dict)))  # True

第二个参数传元组,满足其一就返回 True

Tip

判断类型时,优先用 isinstancetype(x) == SomeClass 在继承场景下会误判。

hasattr()、getattr()、setattr()

这三个函数用来动态操作对象的属性:

class Person:
    def __init__(self, name):
        self.name = name

p = Person('张三')

print(hasattr(p, 'name'))      # True
print(hasattr(p, 'age'))       # False

print(getattr(p, 'name'))      # 张三
print(getattr(p, 'age', 0))    # 属性不存在时返回默认值 0

setattr(p, 'age', 25)
print(p.age)                   # 25

getattr 的第三个参数是默认值。如果不给,属性不存在时会抛 AttributeError

这些函数在写框架、序列化库时特别常用。你不必提前知道对象有什么属性,运行时探测即可。

dir():列出对象的所有属性和方法

s = 'hello'
print(dir(s))
# ['__add__', '__class__', ... , 'upper', 'zfill']

dir() 返回一个字符串列表,包含对象的所有属性和方法名,包括双下划线的特殊方法。它非常适合在交互式环境里快速探索一个对象。

对于自己写的类,dir() 同样有效:

class Demo:
    def __init__(self):
        self.x = 1

    def foo(self):
        pass

d = Demo()
print(dir(d))
# ['__class__', ..., 'foo', 'x']

实例属性 vs 类属性:再深入

31 章简单提过类属性,这里彻底讲清楚。

查找顺序

当你访问 obj.attr 时,Python 按这个顺序查找:

  1. 先在实例 obj__dict__ 里找
  2. 找不到,再去类 type(obj)__dict__ 里找
  3. 还找不到,沿继承链向上找
class Counter:
    count = 0

c = Counter()
print(c.count)   # 0(实例里没有,去类里找)

c.count = 10
print(c.count)   # 10(实例里有了,优先用实例的)
print(Counter.count)  # 0(类属性本身没变)

c.count = 10 不是修改类属性,而是给实例 c 新建了一个同名属性。之后访问 c.count,实例属性会「遮挡」类属性。

用类属性做共享状态

类属性所有实例共享,适合放「全局计数器」之类的数据:

class ConnectionPool:
    active_count = 0

    def __init__(self):
        ConnectionPool.active_count += 1

    def close(self):
        ConnectionPool.active_count -= 1

p1 = ConnectionPool()
p2 = ConnectionPool()
print(ConnectionPool.active_count)  # 2

p1.close()
print(ConnectionPool.active_count)  # 1
Warning

对于可变对象(列表、字典),类属性作为共享状态时要特别小心:

class Bad:
    items = []  # 所有实例共享同一个列表!

a = Bad()
b = Bad()
a.items.append(1)
print(b.items)  # [1]  —— b 也被改了

如果每个实例需要独立的数据,务必在 __init__ 里初始化:self.items = []

__slots__ 节省内存(预告)

默认情况下,每个实例都有一个 __dict__ 字典来存属性,这很灵活,但内存开销大。如果你需要创建大量实例,可以用 __slots__ 限制属性名,从而省内存。

class Point:
    __slots__ = ('x', 'y')

    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2)
# p.z = 3  # AttributeError: 'Point' object has no attribute 'z'

__slots__ 会在第 35 章详细讲,这里先混个脸熟。

实战:写一个属性检查工具

把学到的内省函数串起来,写个小工具:

def inspect_obj(obj):
    print(f"类型: {type(obj).__name__}")
    print(f"属性列表:")
    for name in dir(obj):
        if not name.startswith('__'):
            attr = getattr(obj, name)
            kind = '方法' if callable(attr) else '属性'
            print(f"  - {name} ({kind})")

class Car:
    wheels = 4

    def __init__(self, brand):
        self.brand = brand

    def run(self):
        print(f"{self.brand} 在行驶")

c = Car('比亚迪')
inspect_obj(c)

这个工具能自动列出对象的公开属性和方法,调试时很有用。

小结

  • type() 看精确类型;isinstance() 考虑继承,优先用它。
  • hasattr() / getattr() / setattr() 动态操作属性。
  • dir() 列出所有属性和方法,适合探索未知对象。
  • 实例属性存在 __dict__ 里,类属性存在类的 __dict__ 里。
  • 访问属性时,实例优先于类。修改实例属性不会触及类属性。

这些内省工具就像医生的听诊器,让你能「看见」代码内部的状态。写复杂系统时,它们是排查问题的利器。


来源:参考了 runoob「Python3 面向对象」、liaoxuefeng「获取对象信息」和「实例属性和类属性」、pythondoc「9. 类」等,改写后所得。