一、核心速查表

函数 返回类型 本质含义 是否有值 主要用途 常见坑点
vars(obj) dict obj.__dict__ ✅ 有值 查看/修改对象的实例属性 仅限有 __dict__ 的对象
dir(obj) list[str] 对象的所有属性名 ❌ 无值 探索对象“有什么” 不包含值,顺序无意义
locals() dict 当前局部作用域变量表 ✅ 有值 查看当前函数/模块的局部变量 函数内修改不一定生效
globals() dict 当前全局作用域变量表 ✅ 有值 查看/修改全局变量 模块级别才是真正的全局

二、逐个深度拆解


1️⃣ vars() ——「对象的属性字典」

✅ 核心定义
vars(obj) == obj.__dict__

👉 返回对象的可写属性字典

✅ 适用对象
  • 自定义类的实例
  • 类本身
  • 模块
❌ 不适用对象
vars(1)
vars("abc")
vars([1, 2])

原因:内置类型没有 __dict__

✅ 经典示例
class Person:
    def __init__(self, name):
        self.name = name

p = Person("Alice")

print(vars(p))     # {'name': 'Alice'}
print(p.__dict__)  # {'name': 'Alice'}
⚠️ 重要特性
d = vars(p)
d["age"] = 18
print(p.age)  # 18(原地修改)

返回的是同一个 dict,不是拷贝


2️⃣ dir() ——「对象的属性清单」

✅ 核心定义

返回一个字符串列表,列出对象“能访问到的所有属性名”

✅ 特点
  • 包含:
    • 实例属性
    • 类属性
    • 继承的方法
    • 魔术方法(__xxx__
  • 不包含属性值
✅ 示例
class A:
    x = 1
    def foo(self): pass

a = A()

print(dir(a))
# ['__class__', '__delattr__', ..., 'foo', 'x']
✅ 调试神器
print([x for x in dir(obj) if not x.startswith("__")])
⚠️ 注意
dir(int)      # 能看到 int 的所有方法
vars(int)     # ✅ 有(类属性)
vars(1)       # ❌ 报错

dir() 永远不报错


3️⃣ locals() ——「当前局部作用域」

✅ 核心定义

返回当前作用域中所有“局部变量”组成的字典

✅ 不同场景的行为
① 在模块顶层
a = 1
b = 2

print(locals() is globals())  # True
② 在函数内部
def foo():
    x = 10
    y = 20
    print(locals())

foo()
# {'x': 10, 'y': 20}
⚠️ 超级重要(面试高频)
def foo():
    x = 10
    locals()["x"] = 99
    print(x)  # 10(不会变!)

函数中的 locals() 是只读快照
❌ 修改不会影响真实局部变量


4️⃣ globals() ——「当前全局作用域」

✅ 核心定义

返回当前模块命名空间的字典

✅ 特点
  • 包含:
    • 全局变量
    • 导入的模块
    • 定义的类和函数
  • 可写
✅ 示例
x = 100

def bar():
    globals()["x"] = 999

bar()
print(x)  # 999 ✅
✅ 动态创建全局变量(慎用)
globals()["new_var"] = 123
print(new_var)  # 123

三、四者关系一张图(逻辑视角)

作用域 / 对象
├── 模块
│   ├── globals() → 模块级变量
│   ├── locals()  → 同 globals()
│   ├── vars()    → 模块.__dict__
│   └── dir()     → 模块所有属性
│
├── 函数
│   ├── globals() → 模块级
│   ├── locals()  → 函数局部变量(只读)
│   └── dir()     → 当前作用域可见名字
│
└── 对象
    ├── vars(obj) → 实例属性字典
    └── dir(obj)  → 所有可访问属性名

四、一句话记忆法

🔑 vars = 属性字典(有值)

🔑 dir = 属性名单(有名)

🔑 locals = 眼前变量(局部)

🔑 globals = 文件级变量(全局)


五、常见面试 & 实战问答

Q1:vars()dir() 哪个更常用?

调试用 vars(),探索用 dir()

Q2:为什么函数里改 locals() 没用?

✅ 因为 CPython 的局部变量是静态槽位,不是 dict

Q3:__slots__ 为什么不能用 vars()

✅ 因为 __slots__ 禁用了 __dict__

Q4:globals() 能改别人模块吗?

❌ 不能,只能改当前模块


六、终极对照示例

x = 1

class Demo:
    y = 2
    def __init__(self):
        self.z = 3

d = Demo()

print(vars(d))     # {'z': 3}
print(dir(d))      # [... 'y', 'z']
print(locals())    # 包含 x, Demo, d
print(globals())   # 同 locals()

更多推荐