Reputation: 18790
when I was implementing naive singleton in python, I came up with a problem with super key word. As usual the behavior of super is always tricky and buggy, hope someone can shed light on it. Thanks :)
The problem is that:
class Singleton(object):
def __new__(cls,*args,**kw):
if not hasattr(cls,'_instance'):
#create a instance of type cls,
origin=super(Singleton,Singleton).__new__(cls,*args,**kw)
cls._instance=origin
return cls._instance
class B(Singleton):
def __init__(self,b):
self.b=b
It actually works, but I am wondering
Will it be better if I change line 5 to the below, like in most of the books?
origin=super(Singleton,cls).__new__(cls,*args,**ks)
what's the difference to make?
Upvotes: 1
Views: 308
Reputation: 1123072
super()
searches the MRO of the current object for the next class that has the requested attribute. The first argument to super()
determines the starting point for the MRO search, the second argument determines the object from which to take the MRO.
As long as you don't use multiple inheritance, your MRO will be straightforward. Singleton
will always be in the same location in the MRO in that case. With multiple inheritance, where Singleton
appears in the MRO of the subclass will differ, and you really want to use cls
to get the current MRO, not the MRO of just Singleton
.
For your simple example, ignoring cls
(e.g. B
) is fine:
>>> class Singleton(object):
... def __new__(cls,*args,**kw):
... if not hasattr(cls,'_instance'):
... #create a instance of type cls,
... origin=super(Singleton,Singleton).__new__(cls,*args,**kw)
... cls._instance=origin
... return cls._instance
...
>>> class B(Singleton):
... def __init__(self,b):
... self.b=b
...
>>> B.__mro__
(<class '__main__.B'>, <class '__main__.Singleton'>, <type 'object'>)
>>> Singleton.__mro__
(<class '__main__.Singleton'>, <type 'object'>)
So super(Singleton, Singleton)
and super(Singleton, cls)
end up searching through the same sublist, finding only object
.
Use multiple inheritance however, and you'll get a very different MRO; note that Foo
is listed between Singleton
and object
:
>>> class Foo(object): pass
...
>>> class Bar(Singleton, Foo): pass
...
>>> Bar.__mro__
(<class '__main__.Bar'>, <class '__main__.Singleton'>, <class '__main__.Foo'>, <type 'object'>)
If you use super(Singleton, Singleton)
, then Foo
is inadvertently skipped when looking for inherited methods. super(Singleton, cls)
will search through (Foo, object)
, super(Singleton, Singleton)
will only look at object
.
Upvotes: 2