Python详解如何动态给对象增加属性和方法

发布时间:2026/10/12 14:02:47
Python详解如何动态给对象增加属性和方法 前言运行时给一个对象加属性是这门语言相当有辨识度的能力不用改类定义obj.new_field 1一句就加上了。更进一步还能给对象或类动态挂上一个方法让它在某一刻学会新行为。很多教程把这件事讲成Python 很灵活但很少讲清代价——动态加属性会让对象结构不可预测给调试、序列化和维护都埋雷。这里还有个高频误解以为给实例加方法和给类加方法是一回事。不是。给类加函数任何实例调用时都会自动绑定self给实例加函数它只是个普通属性不会自动绑定调用时得自己传参除非用types.MethodType显式绑定。本文把这两条路分开讲清楚示例基于 Python 3.8。一、普通对象都有 __dict__默认情况下实例的属性存在一个字典obj.__dict__里。可以直接看、也能直接改# 适用于 Python 3.8class User:def __init__(self, name):self.name nameu User(小明)print(u.__dict__) # {name: 小明}u.age 18 # 动态加属性u.__dict__[city] 北京 # 直接改字典也能加print(u.__dict__) # {name: 小明, age: 18, city: 北京}obj.__dict__是实例自己的命名空间和类的Cls.__dict__是两本账。属性查找时先看实例这本再看类那本。二、setattr / getattr / hasattr / delattr直接用点号obj.x 1适合属性名在写代码时就确定的情况属性名是字符串、运行时才知道时要用这四个内置函数# 适用于 Python 3.8class Config:passc Config()key timeoutsetattr(c, key, 30) # 等价于 c.timeout 30print(getattr(c, key)) # 30print(getattr(c, missing, None)) # None给默认值就不抛异常print(hasattr(c, timeout)) # Truedelattr(c, key) # 等价于 del c.timeoutprint(hasattr(c, timeout)) # False四个函数签名固定setattr(obj, name, value)、getattr(obj, name[, default])、hasattr(obj, name)、delattr(obj, name)。注意getattr的默认值是第三个参数不是关键字不给默认值时属性不存在会抛AttributeError。hasattr在属性访问过程中如果抛出别的异常比如 property 里出错行为要小心——它会把非AttributeError的异常正常抛出。三、给实例加还是给类加这一点必须分清操作效果范围是否自动绑定selfinst.attr v只有这个实例不涉及Cls.attr v该类及所有子类的所有实例不涉及inst.method func只有这个实例否是普通函数Cls.method func该类及其所有实例是函数变方法# 适用于 Python 3.8class Robot:passr1, r2 Robot(), Robot()# 给类加属性两个实例都看得到Robot.model X1print(r1.model, r2.model) # X1 X1# 给实例加属性只有自己有r1.serial A001print(hasattr(r2, serial)) # False原因在于Cls.method这种赋值把函数放进了类字典函数是描述符descriptor通过实例访问时会被绑定成方法而inst.method func只是往实例字典塞了个普通对象没有绑定过程。四、给对象动态加方法给类加方法最简单直接把函数赋给类属性# 适用于 Python 3.8class Greeter:def __init__(self, name):self.name namedef greet(self):return f你好我是 {self.name}Greeter.greet greet # 函数进类字典自动绑定g Greeter(小红)print(g.greet()) # 你好我是 小红给单个实例加方法就得显式绑定因为实例字典里的函数不会自动获得self# 适用于 Python 3.8import typesclass Greeter:def __init__(self, name):self.name namedef greet(self):return f你好我是 {self.name}g Greeter(小刚)g.greet types.MethodType(greet, g) # 把函数绑定到这个实例print(g.greet()) # 你好我是 小刚types.MethodType就是文档里说的用户自定义类实例的方法类型用它构造出来的对象已经记住了绑定实例所以调用时不用再传self。不绑定直接写g.greet greet的话g.greet()会抛TypeError因为greet需要一个位置参数而没收到。五、__slots__ 会禁止动态属性如果类声明了__slots__它的实例没有__dict__动态加属性会被直接拒绝# 适用于 Python 3.8class Point:__slots__ (x, y)def __init__(self, x, y):self.x, self.y x, yp Point(1, 2)p.x 10 # 已在 __slots__ 中可以改try:p.z 3 # 未声明禁止except AttributeError as e:print(拒绝, e)try:print(p.__dict__) # 没有 __dict__except AttributeError as e:print(也没有 __dict__, e)要在__slots__的类上动态加属性可以额外把__dict__放进__slots__这样会重新引入实例字典省内存的好处就没了或者干脆不用__slots__。用不用__slots__本质是属性集合固定、省内存与灵活可扩展之间的取舍。常见坑点坑 1以为给实例赋函数就等于加了方法。❌g.greet greet然后g.greet()—— 函数未绑定抛TypeError: greet() missing 1 required positional argument: self。✅ 用types.MethodType(greet, g)绑定或把函数加在类上。坑 2给一个实例加属性却以为所有实例都有。❌r1.serial A001后访问r2.serial——AttributeError。✅ 要全体共享就在类上定义或写进__init__。坑 3在__slots__的类上动态加属性。❌ 给__slots__的实例写p.z 3——AttributeError。✅ 确认类的属性集合需要动态就把它加进__slots__或改用普通类。坑 4用hasattr判断属性却忽略它会触发属性访问。❌ 对带property的对象反复hasattr—— 每次都会执行 getter可能有副作用。✅ 明确用getattr(obj, name, default)或检查__dict__/__class__避免意外触发计算。坑 5动态属性名拼错静默出错。❌ 用字符串setattr(obj, nmae, v)拼错名字程序不报错后面取值拿到None。✅ 属性名来自变量时要加校验或集中管理能写死的属性名就直接写。坑 6动态加属性破坏序列化。❌ 默认序列化工具按__dict__存运行时加的字段可能被漏掉或结构不一致。✅ 明确对象的固定字段集合不依赖临时加字段来做数据传递。坑 7在方法里忘了用setattr直接对名字赋值。❌ 想给对象加属性却写成timeout 30—— 那只是创建了一个局部变量。✅ 用self.timeout 30或setattr(self, timeout, 30)。总结想做的事正确写法加一个已知属性obj.attr value加一个名字是变量的属性setattr(obj, name, value)读属性、缺了给默认值getattr(obj, name, default)给所有实例加方法Cls.method func自动绑定给单个实例加方法obj.method types.MethodType(func, obj)禁止动态属性声明__slots__删除属性del obj.attr或delattr(obj, name)一句话总结动态加属性靠的是实例的__dict__动态加方法的关键是函数是不是通过类访问——通过类访问会被绑定成方法通过实例字典放进去则不会。这套能力很灵活但灵活性要和可维护性权衡字段集合固定的对象明确在__init__里或__slots__里写清楚比到处临时加一个更可靠。版本说明types.MethodType、setattr系列在 Python 3 中行为一致。Python 2 里旧式类不支持__slots__与部分描述符特性且 Python 2.7 已于 2020 年 1 月 1 日停止维护新代码只写 Python 3。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询