为何__new__方法需用cls而非args[0]?RuntimeError原因解析
核心原因:无参数super()依赖Python的隐式上下文绑定
Python里无参数的super()不能随便用,它要求函数定义时的第一个参数是约定好的标识符——类方法(比如__new__)里的cls,或者实例方法里的self。Python会通过这个参数自动绑定当前类/实例的上下文,让super()能定位到父类的对应方法。
两个类的差异分析
Klass2的写法:
__new__(cls, *args)符合Python对类构造方法的参数约定,Python会自动把当前类(Klass2)绑定到cls参数上。这时候调用super(),Python能直接从cls参数获取上下文,super().__new__(cls)就能正常找到父类的__new__方法,运行无问题。Klass1的写法:
__new__(*args)把所有参数打包成元组args,Python没办法识别args[0]就是当前类——因为*args是通用参数打包,没有cls这种约定好的标记。这时候无参数的super()找不到必要的上下文信息(不知道当前是哪个类,也找不到对应的绑定关系),就会抛出RuntimeError: super(): no arguments异常。
补充:不是值的问题,是参数约定的问题
你可能会疑惑,Klass1里args[0]的值明明就是Klass1,为啥和cls不一样?因为无参数super()的工作逻辑是看函数定义时的参数结构,而不是运行时传入的值。它需要Python自动注入的上下文,*args破坏了这个自动注入的前提,哪怕你手动取args[0]当类,super()也没法拿到它需要的上下文。
如果要让Klass1正常运行,可以改成显式给super()传参数:
class Klass1(): def __new__(*args): obj = super(args[0], args[0]).__new__(args[0]) return obj
不过更规范的写法还是像Klass2那样,用cls作为第一个参数。
内容的提问来源于stack exchange,提问作者Toothpick Anemone

