28

I came upon this reading the python documentation on the super keyword:

If the second argument is omitted, the super object returned is unbound. If the second argument is an object, isinstance(obj, type) must be true. If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods).

Can someone please give me an example of a distinction between passing a Type as a second argument versus passing an Object?

Is the documentation talking about an instance of an object?

Thank you.

laycat
  • 5,381
  • 7
  • 31
  • 46
claudio
  • 1,465
  • 16
  • 26
  • 9
    This should give you some perspective: http://www.cafepy.com/article/python_types_and_objects/python_types_and_objects.html#object-type-example – karthikr Mar 30 '13 at 06:17
  • @karthikr Agreed, great article – jamylak Mar 30 '13 at 06:20
  • 3
    Or have a look at this question http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python?rq=1 and the great answer , whilst its about metaclasses it details types and objects to build up the description of a metaclass - really good read. – Tim Hoffman Mar 30 '13 at 06:39
  • Such an awesome question. I've been trying teach my self OOP in Python (my only language), grappling with using inheritance and calling superclass methods. I read that explanation about super had the same question. – cfwschmidt Aug 12 '14 at 11:22
  • This is not exactly a duplicate. Technically it is, but say, ergonomically, I don't think so. I think this answer deserves a different focus than only an explanation about metaclasses. For example, it could lead to discussing why object evaluates as an instance of type, and type also evaluates as an instance of object. @MartijnPieters –  Sep 06 '18 at 19:50
  • I think this is a much better duplicate https://stackoverflow.com/questions/44835369/what-are-the-relations-between-classes-type-and-object –  Sep 06 '18 at 19:57

3 Answers3

11

Python's super function does different things depending on what it's arguments are. Here's a demonstration of different ways of using it:

class Base(object):
    def __init__(self, val):
        self.val = val

    @classmethod
    def make_obj(cls, val):
        return cls(val+1)

class Derived(Base):
    def __init__(self, val):
        # In this super call, the second argument "self" is an object.
        # The result acts like an object of the Base class.
        super(Derived, self).__init__(val+2)

    @classmethod
    def make_obj(cls, val):
        # In this super call, the second argument "cls" is a type.
        # The result acts like the Base class itself.
        return super(Derived, cls).make_obj(val)

Test output:

>>> b1 = Base(0)
>>> b1.val
0
>>> b2 = Base.make_obj(0)
>>> b2.val
1
>>> d1 = Derived(0)
>>> d1.val
2
>>> d2 = Derived.make_obj(0)
>>> d2.val
3

The 3 result is the combination of the previous modifiers: 1 (from Base.make_obj) plus 2 (from Derived.__init__).

Note that it is possible to call super with just one argument to get an "unbound" super object, it is apparently not useful for much. There's not really any reason to do this unless you want to mess around with Python internals and you really know what you're doing.

In Python 3, you can also call super with no arguments (which is equivalent to the calls in the functions above, but more magical).

Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • Is super a way to help with Memoization of function calls? I have an object that speeds up calls to another interpreter by checking for the functions existence and then assigning an attribute on the object with an object that directly calls the function. So I basically only lookup the function once and memoize it to a callable attribute. I have to use object.__setattr__(self, "attribute", callableObj) in order to keep it from looping/calling my redefinition of "__settr__". Does super do the same thing? – Demolishun Mar 30 '13 at 22:23
  • @Demolishun: Um, no. You use `super` to get at inherited versions of overridden methods. Check out [the docs](http://docs.python.org/2/library/functions.html#super) – Blckknght Mar 31 '13 at 00:18
  • Okay, so it is similar, but it allows for dynamic reference of the base class, but not by name. That is one use case. http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ Thanks for the ref. – Demolishun Mar 31 '13 at 22:41
0

Object can be any Python class instance which may or may not be user defined. But, when you are talking about a type, it refers to the default objects/collections like a list/tuple/dict/int/str etc.

smitkpatel
  • 11
  • 2
0

Here is a simple exploration of the two functions. I found it illuminating going through this exercise. I often will create a simple program exploring the ins and outs of simple functions and save them for reference:

#
# Testing isinstance and issubclass
#

class C1(object):
    def __init__(self):
        object.__init__(self)

class B1(object):
    def __init__(self):
        object.__init__(self)

class B2(B1):
    def __init__(self):
        B1.__init__(self)

class CB1(C1,B1):
    def __init__(self):
        # not sure about this for multiple inheritance
        C1.__init__(self)
        B1.__init__(self)

c1 = C1()
b1 = B1()
cb1 = CB1()

def checkInstanceType(c, t):
    if isinstance(c, t):
        print c, "is of type", t
    else:
        print c, "is NOT of type", t

def checkSubclassType(c, t):
    if issubclass(c, t):
        print c, "is a subclass of type", t
    else:
        print c, "is NOT a subclass of type", t

print "comparing isinstance and issubclass"
print ""

# checking isinstance
print "checking isinstance"

# can check instance against type
checkInstanceType(c1, C1)
checkInstanceType(c1, B1)
checkInstanceType(c1, object)

# can check type against type
checkInstanceType(C1, object)
checkInstanceType(B1, object)

# cannot check instance against instance
try:
    checkInstanceType(c1, b1)
except Exception, e:
    print "failed to check instance against instance", e

print ""

# checking issubclass
print "checking issubclass"

# cannot check instance against type
try:
    checkSubclassType(c1, C1)
except Exception, e:
    print "failed to check instance against type", e

# can check type against type
checkSubclassType(C1, C1)
checkSubclassType(B1, C1)
checkSubclassType(CB1, C1)
checkSubclassType(CB1, B1)

# cannot check type against instance
try:
    checkSubclassType(C1, c1)
except Exception, e:
    print "failed to check type against instance", e

Edit: Also consider the following as isinstance can break API implementations. An example would be an object that acts like a dictionary, but is not derived from dict. isinstance might check that an object is a dictionary, even though the object supports dictionary style access: isinstance considered harmful

Edit2:

Can someone please give me an example of a distinction between passing a Type as a second argument versus passing an Object?

After testing the above code it tells me the second parameter must be a type. So in the following case:

checkInstanceType(c1, b1)

The call will fail. It could be written:

checkInstanceType(c1, type(b1))

So if you want to check the type of one instance against another instance you have to use the type() builtin call.

Tomasz Jakub Rup
  • 10,502
  • 7
  • 48
  • 49
Demolishun
  • 1,592
  • 12
  • 15