定义类方法时忘记写self参数会报TypeError: xxx() takes 0 positional arguments but 1 was given;__init__必须有self才能绑定属性,否则触发NameError;类变量误用可变对象会导致实例间数据共享。

class 定义时忘记写 self 参数会报什么错
直接运行会抛出 TypeError: xxx() takes 0 positional arguments but 1 was given —— 这是因为 Python 自动把实例本身当第一个参数传进去了,但你没在方法签名里留位置。
常见于刚写 __init__ 或普通方法时漏掉 self。别指望 IDE 总能帮你补全,尤其在快速复制粘贴代码时容易带进来空参数列表。
-
__init__必须有self,否则无法绑定属性,比如self.name = name会直接报NameError - 静态方法(
@staticmethod)和类方法(@classmethod)是例外,它们不自动传实例,但得显式声明cls或完全不写参数 - 如果真想定义一个不依赖实例的函数,就别塞进
class里,单独写个普通函数更干净
实例化对象时传参失败的典型场景
最常踩的坑是:定义了 __init__(self, name, age),但调用时写成 Person() 或 Person("Alice"),少传、多传、顺序错都会触发 TypeError。
Python 不支持参数重载,也没有默认值兜底——除非你主动设默认值。
立即学习“Python免费学习笔记(深入)”;
- 给参数加默认值(如
age=0)能缓解调用压力,但别滥用,容易掩盖设计意图 - 用
*args和**kwargs接收不确定参数时,记得在__init__里做类型/存在性校验,不然 runtime 错误更难 debug - 如果构造逻辑复杂(比如要读配置、连数据库),考虑用类方法做替代构造器,比如
Person.from_json(...)
__str__ 和 __repr__ 到底该返回啥
__str__ 是给人看的,__repr__ 是给开发者/调试器看的。打错一个,print 或日志里就全是 <__main__.Person object at 0x...> 这种无意义地址。
不实现它们不是语法错误,但会让调试成本陡增。
-
__str__返回简洁可读字符串,比如f"{self.name} ({self.age})" -
__repr__应尽量返回能重建对象的表达式,比如f"Person(name={self.name!r}, age={self.age})";注意用!r保证引号和转义正确 - 如果懒得写两个,至少实现
__repr__,print()在找不到__str__时会 fallback 到它
类变量 vs 实例变量:一个 = 引发的共享问题
写 count = 0 在 class 下是类变量,所有实例共享;写 self.count = 0 在 __init__ 里才是独立实例变量。新手常在这儿翻车,比如计数器莫名其妙变大、列表 append 全实例一起涨。
典型错误现象:obj1.items.append("a") 后,obj2.items 也多了 "a"。
- 可变对象(list、dict、set)绝不能直接定义为类变量,除非你明确需要全局共享状态
- 不可变对象(int、str、tuple)作为类变量相对安全,但修改时其实是创建新对象并绑定到实例,容易混淆行为预期
- 拿不准时,统一在
__init__里初始化所有属性,最省心


















