Reputation: 3271
Before you mark it as duplicate, let me state that I understand how super works and I have read these three links:
What does 'super' do in Python?
Understanding Python super() with __init__() methods
http://python-history.blogspot.nl/2010/06/method-resolution-order.html
This is how super
is supposed to work in case of baseclasses
:
class X(object):
def __init__(self):
print "calling init from X"
super(X, self).__init__()
class Y(object):
def abc(self):
print "calling abc from Y"
super(Y, self).abc()
a = X()
# prints "calling init from X" (works because object possibly has an __init__ method)
b = Y()
b.abc()
# prints "calling abc from Y" and then
# throws error "'super' object has no attribute 'abc'" (understandable because object doesn't have any method named abc)
Question: In django
core implementation, there are several places where they call methods
using super
on classes inheriting from object
(case Y
in my example above). For example: can someone explain me why this code works?
from django.core.exceptions import PermissionDenied
class LoginRequiredMixin(object):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated():
raise PermissionDenied
return super(LoginRequiredMixin, self).\
dispatch(request, *args, **kwards) # why does this work?
Ref: copied this code from this talk: https://youtu.be/rMn2wC0PuXw?t=403
Upvotes: 1
Views: 1788
Reputation: 6893
It works because LoginRequiredMixin is intended to be used in a multiple inheritance scenario. In this case, the MRO would resolve to the object in the same level of the class hierarchy. (The other type specified alongside LoginRequiredMixin)
You can see below that the order matters too
Python 2.7.12 (default, Oct 11 2016, 05:20:59)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>>
>>> class Y(object):
... def abc(self):
... print "calling abc from Y"
... super(Y, self).abc()
...
>>> class Z(object):
... def abc(self):
... print "calling abc from Z"
...
>>> class YZ(Y, Z): # multiple inheritance
... pass
...
>>> c = YZ()
>>> c.abc()
calling abc from Y
calling abc from Z
>>>
>>> class ZY(Z,Y): pass
...
>>> ZY().abc()
calling abc from Z
ZY
calls Z.abc
based on MRO so Y.abc
is ignored
Upvotes: 2
Reputation: 25789
Have you tested all the code in that presentation? The code above may work only if somebody is doing something that shouldn't be done (and in some Python implementations is strictly forbidden) behind the scenes - modifying Python builtins.
You can do it, too - before you get to execute or build anything, do this:
import __builtin__
class custom_object(object):
def abc(self):
print "calling abc from custom_object"
__builtin__.object = custom_object
Then try building your X
and Y
types and see how it goes.
P.S. Just to emphasize something, this is presented for educational purposes only - DO NOT USE THIS! There really is no need to ever resort to this and you'd just make life a living hell for developers who might need to untangle your code in the future.
UPDATE:
As per Josh J's suggestion above, LoginRequiredMixin
might not be intended to be used as a standalone class but added in a multiple-inheritance chain. In that scenario a base class, which implements dispatch()
method and extends object
, can be glued to the LoginRequiredMixin
. Taking into the account how Python's does MRO, super()
from LoginRequiredMixin
will actually refer to the 'glued' class' methods.
You can get your code to behave the same like:
class Y(object):
def abc(self):
print "calling abc from Y"
super(Y, self).abc()
class Z(object):
def abc(self):
print "calling abc from Z"
class YZ(Y, Z): # multiple inheritance
pass
c = YZ()
c.abc()
# prints "calling abc from Y" and then
# prints "calling abc from Z"
It still is a sign of bad framework design (just consider how long it took us to get to the bottom of the issue based on quite simple code), just slightly less atrocious than messing with builtins. So, if you're designing your framework one day DO NOT DO THIS, EITHER.
Upvotes: 1