SortedListclass SimpleList:
def __init__(self, items):
self._items = list(items)
def add(self, item):
self._items.append(item)
def __getitem__(self, index):
return self._items[index]
def sort(self):
self._items.sort()
def __len__(self):
return len(self._items)
def __repr__(self):
return "SimpleList({!r})".format(self._items)
class SortedList(SimpleList):
def __init__(self, items=()): # optional sequence argument
super().__init__(items)
self.sort()
def add(self, item):
super().add(item)
self.sort()
def __repr__(self):
return "SortedList({!r})".format(list(self))
class IntList(SimpleList):
def __init__(self, items=()):
for x in items: self._validate(x)
super().__init__(items)
@staticmethod
def _validate(x):
if not isinstance(x, int):
raise TypeError('IntList only supports integer values.')
def add(self, item):
self._validate(item)
super().add(item)
def __repr__(self):
return "IntList({!r})".format(list(self))
class SortedIntList(IntList, SortedList):
def __repr__(self):
return "SortedIntList({!r})".format(list(self))Useful built-in functions:
isinstance()
True if object is a subclass of specified type# in repl
>>> isinstance(3, int)
#=> True
>>> isinstance('hello!', str)
#=> True
>>> x = []
>>> isinstance(x, (float, dict, list))
#=> Trueissubclass()
class BaseClass:
def __init__(self, foo):
self.foo = foo
class SubClass(BaseClass):
def __init__(self, foo, bar):
super().__init__(foo)
self.bar = bar
class SubSubClass(SubClass):
def __init__(self, foo, bar, baz):
super().__init__(foo, bar)
self.baz = baz
issubclass(BaseClass, SubClass)
#=> False
issubclass(SubClass, BaseClass)
#=> True
issubclass(SubSubClass, BaseClass)
#=> TrueSingle inheritance
class SubClass(BaseClass):
passMultiple inheritance
class SubClass(Base1, Base2, . . .):
pass__bases__ member of class objects
__mro__ member
mro() to get the order as a list rather than a tupleWhen you call a method on an object in Python...
C3 - algorithm for calculating MRO in Python - ensures that - subclasses come before base classes - base class order from class definition is preserved - first two qualities are preserved no matter where you start in the inheritance graph - because of the above criteria, not all inheritance declarations are allowed!
# Example of multiple inheritance that violates C3
>>> class A:
... pass
>>> class B(A):
... pass
>>> class C(A):
... pass
>>> class D(B, A, C):
... pass
#=> TypeError: Cannot create a consistent method resolution order (MRO) for bases A, CExplanation of above:
- since B and C both inherit from A, B and C must both come before A in any MRO
- however, since D's base class declaration puts A before C, and since C3 also guarantees that base class declaration order is preserved, C3 cannot produce a consistent MRO, as it can't put A both before and after C
super() FunctionShort, albeit incomplete, definition: given a method resolution order and a class C, super() gives you an object which resolves methods using only the part of the MRO which comes after C
super() returns a proxy object which routes method calls
two types of bound proxies:
super(base-class, derived-class)
base-class is class objectderived-class is subclass of first argument**Explanation using SortedList example
>>> from sorted_list import *
>>> from pprint import pprint as pp
>>> pp(SortedIntList.mro())
#=> [
#=> <class 'sorted_list.SortedIntList'>,
#=> <class 'sorted_list.IntList'>,
#=> <class 'sorted_list.SortedList'>,
#=> <class 'sorted_list.SimpleList'>,
#=> <class 'object'>,
#=> ]
>>> super(SortedList, SortedIntList)
#=> <super: <class 'SortedList'>, <SortedIntList object>>
#=> --------- NAME RESOLUTION ---------
#=> 1. gets MRO for 'SortedIntList'
#=> 2. finds 'SortedList' in that MRO
#=> 3. takes everything after 'SortedList', giving us an MRO of containing just 'SimpleList' and 'object'
#=> 4. finds first class in that smaller MRO which has an 'add' method
>>> super(SortedList, SortedIntList).add
#=> <function SimpleList.add at 0x10436a050>
>>> super(SortedList, SortedIntList).add(4)
#=> TypeError: add() missing 1 required positional argument: 'item'
# ^^^^^^^^ raised because our proxy is bound to a class, not an instance
#
# However, we could invoke the method with our proxy if it's a static method or class method, like so:
>>> super(SortedList, SortedIntList)._validate(5)
>>> super(SortedList, SortedIntList)._validate('hello')
#=> TypeError: IntList only supports integer values.super(class, instance-of-class)
class is class objectinstance-of-class must be instance of class or any class derived from it>>> from sorted_list import *
>>> from pprint import pprint as pp
>>> pp(SortedIntList.mro())
#=> [
#=> <class 'sorted_list.SortedIntList'>,
#=> <class 'sorted_list.IntList'>,
#=> <class 'sorted_list.SortedList'>,
#=> <class 'sorted_list.SimpleList'>,
#=> <class 'object'>,
#=> ]
>>> sil = SortedIntList([5, 15, 10])
>>> sil
#=> SortedIntList([5, 10, 15])
>>> super(SortedList, sil)
#=> <super: <class 'SortedList'>, <SortedIntList object>>
>>> super(SortedList, sil).add(6)
>>> sil
#=> SortedIntList([5, 10, 15, 6]) --- Not quite 🙃super() Without ArgumentsWhen calling super() without arguments, Python will sort out arguments for you
super(class-of-method, self)super(class-of-method, class)object Class