Python重写__new__限制实例数:代码疑问解析
我在阅读一篇关于Python重写__new__方法的博客时,对下面的示例代码存在两个疑问:
class LimitedInstances(object): _instances = [] # Keep track of instance reference limit = 5 def __new__(cls, *args, **kwargs): if not len(cls._instances) <= cls.limit: raise RuntimeError, "Count not create instance. Limit %s reached" % cls.limit instance = object.__new__(cls, *args, **kwargs) cls._instances.append(instance) return instance def __del__(self): # Remove instance from _instances self._instance.remove(self)
疑问点:
- 调用
object.__new__(cls, *args, **kwargs)是否会导致无限递归? - 已知
__new__在对象创建前执行,那么cls中究竟存储的是什么?
解答
1. 为什么调用object.__new__(cls, ...)不会触发无限递归?
这是个非常关键的问题!首先得明确:只有调用当前类的__new__方法才会触发递归,而这里我们直接调用的是object类的__new__——它是所有新式类的顶级基类,不会再回调子类(也就是LimitedInstances)的__new__方法。
举个直白的例子:当你在子类里重写了某个方法,然后直接调用父类的同名方法时,只会执行父类的实现逻辑,不会绕回子类的重写方法。object.__new__的职责就是创建一个最原始的空对象实例,它内部没有任何会调用子类__new__的逻辑,所以完全不会出现无限递归的情况。
反过来,如果我们在LimitedInstances.__new__里写的是cls.__new__(cls, ...),那才会触发无限递归——因为每次调用都会回到当前方法本身,直到栈溢出报错。
2. __new__执行时,cls到底是什么?
cls其实就是当前正在被实例化的类对象本身!
你要知道,Python里的类也是一种对象:当你写完class LimitedInstances(object):这段代码时,Python就已经在内存中创建了一个名为LimitedInstances的类对象,它属于type类型(或者说,是type的实例)。
当你执行LimitedInstances()创建实例时,Python会自动调用LimitedInstances.__new__(LimitedInstances, ...)——这里的第一个参数cls,就是把LimitedInstances这个类对象直接传进来了。这时候虽然实例还没被创建,但类对象已经存在了,所以你可以正常访问cls._instances、cls.limit这些类级别的属性,就像示例代码里做的那样。
简单总结:cls是类本身的引用,让你能在__new__方法里操作类属性、控制实例的创建规则。
另外提个小细节:示例代码里的__del__方法有个笔误,应该是self._instances.remove(self)(原代码写的是self._instance.remove(self),少了一个下划线),不然运行时会抛出属性不存在的错误哦。
内容的提问来源于stack exchange,提问作者user10661584

