1. 反射是什么? #
反射 指在运行时 用字符串去检查、读取对象的属性或方法。
Python 很动态,hasattr / getattr 等内置函数就是反射入口。
全栈项目里:读配置缺省值 、按字段名遍历 Model、读框架源码时会遇到。
业务代码应优先显式属性/方法名 ,少写「字符串拼方法名」的魔法逻辑。
2. 四个核心函数 #
函数
作用
hasattr(obj, "name")
是否有该属性
getattr(obj, "name"[, default])
取值;不存在可返回默认值
setattr(obj, "name", value)
动态设属性(慎用)
dir(obj)
列出名称,调试、探索用
class Settings :
def __init__ (self ):
self .host = "localhost"
self .port = 8080
cfg = Settings()
print (getattr (cfg, "host" ))
print (getattr (cfg, "timeout" , 30 ))
print (hasattr (cfg, "debug" ))
setattr (cfg, "debug" , True )
print (cfg.debug)
项目最常见 :getattr(obj, key, default) 处理可选配置、可选字段。
3. 动态调用方法 #
可用 hasattr 判断方法是否存在,再用 getattr 取出并 callable 检查后调用。
实际项目应对 action 做白名单校验 ,禁止直接用用户输入当方法名。
class UserService :
def list_users (self ):
return [{"name" : "Alice" }, {"name" : "Bob" }]
def create_user (self, name: str ):
return {"name" : name}
svc = UserService()
action = "list_users"
if hasattr (svc, action):
fn = getattr (svc, action)
if callable (fn):
result = fn()
print (result)4. 按名字段访问 #
遍历允许的字段名列表 (白名单),用 getattr(user, field, None) 动态取值。
禁止 把用户传入的字符串直接当属性名,防止访问到不该暴露的字段。
class User :
def __init__ (self, name, email, status ):
self .name = name
self .email = email
self .status = status
user = User("Alice" , "alice@example.com" , "active" )
result = {}
for field in ("name" , "email" , "status" ):
value = getattr (user, field, None )
result[field] = value
print (result)5. 模块动态导入 #
importlib.import_module("包.模块") 按字符串路径动态导入模块。
再用 getattr(module, "类名") 取出类或函数。
用于插件、按配置加载实现类;普通 CRUD 用固定 import 更清晰。
import importlib
module = importlib.import_module("myapp.models.User" )
User = getattr (module, "User" )
user = User()
print (user)6. 内省 #
内省(introspection) 指在运行时检查对象、类型、属性等信息。
type(obj) :获取对象的真实类型。
isinstance(obj, T) :判断对象是不是某类型/其子类。
dir(obj) :列出所有属性和方法名(包含特殊方法)。
vars(obj) :查看对象的属性字典(有些内建对象没有)。
在处理动态数据格式、序列化、ORM 映射等场景,通过 type 、isinstance 区分类型,通过 dir 排查对象接口。
type / isinstance 日常写业务也会用;dir 多用于排查问题。
print (type (user))
print (isinstance (user, User))
print (dir (user))
print (vars (user)) 7. __getattr__ #
访问不存在 的属性时触发 __getattr__(self, name) 。
可用来做配置代理:从内部字典按属性名查找值。
属性名不在字典中时,应 raise AttributeError 。
class Config :
def __init__ (self, data: dict ):
self ._data = data
def __getattr__ (self, name: str ):
if name in self ._data:
return self ._data[name]
raise AttributeError(name)
config = Config({'host' : 'localhost' , 'port' : 3306 })
print (config.host)
print (config.port)
try :
print (config.user)
except AttributeError as e:
print (f"AttributeError: {e} " )8. 项目开发要点 #
首选 :obj.field 、from app.services import UserService 等显式写法。
可选配置 :getattr(settings, "DEBUG", False) 。
动态字段 :字段名列表必须白名单 ,禁止直接用用户输入当属性名。
调用方法 :若用 getattr 取方法,先 callable 再调用,并限制允许的方法名。
可维护性 :反射越多越难静态分析;非必要不用。
9. 总结 #
反射核心:运行时按字符串名访问属性/方法/模块 。
日常以 getattr(..., default) 处理可选配置为主;动态分发须白名单。
下表按 API 速查典型场景。
API
项目场景
getattr(..., default)
缺省配置、可选属性
hasattr
判断是否有某能力再调用
getattr + callable
命令/插件分发(少用)
importlib.import_module
按名加载模块
dir / vars
调试