What is super() function:
So brief history, the super() function was released in python 2.x. Through out the years, super() was redefined a little for python 3.x. The super() function is another way to use inheritance as a special case of overriding where you want to alter the behavior. Here is an example below to make sense of the description:
class Host(object):
def comm(self):
print "Host altered()"
class Client(Parent):
def comm(self):
print "Client, BEFORE Host comm()"
super(Client, self).comm()
print "Client, AFTER Host comm()"
bank = Host()
customer = Client()
bank.comm()
customer.comm()
Important things to note:
- Since Host.comm was overridden, Client.comm will run.
- The super function "super(Client,self).comm()" is aware of inheritance and will get the Parent class for you. One of the benefits of super. You read this as "call super with arguments Client and self, then call the function comm on whatever it returns".
- Now, the Host.comm version of the function runs, and that prints out the Host message
- And Final, this returns from Host.comm and the Client.altered function continues to print out the "AFTER" message
Printout
testBitConsole$python3 superExample.py
Host comm()
Client, BEFORE Host comm()
Host comm()
Client, AFTER Host comm()
Another Super() Example:
class Host(object):
def comm(self):
print("Host comm()")
class subClientA(Host):
def comm(self):
print("subClientA comm()")
super(subClientA, self).comm()
print("subClientA, AFTER subClientA comm()")
class subClientB(Host):
def comm(self):
print("subClientB comm()")
super(subClientB, self).comm()
print("subClientB, AFTER subClientB comm()")
class Client(subClientA,subClientB):
def comm(self):
print("Client, BEFORE Host comm()")
super(Client, self).comm()
print("Client, AFTER Host comm()")
#bank = Host()
customer = Client()
#bank.comm()
customer.comm()
Printout
testBitConsole$ python3 superexample1.py
Client, BEFORE Host comm()
subClientA comm()
subClientB comm()
Host comm()
subClientB, AFTER subClientB comm()
subClientA, AFTER subClientA comm()
Client, AFTER Host comm()
Diamond layout for example above:
Important Note! Host comm() is only printed once even through two classes derive from it. This is due to the method resolution order (MRO) that is inherent in the new style classes of Python
Here is a excerpt describing MRO and Inheritance:
With multiple inheritance comes the question of method resolution order: the order in which a class and its bases are searched looking for a method of a given name.
In classic Python, the rule is given by the following recursive function, also known as the left-to-right depth-first rule:
def classic_lookup(cls, name):
"Look up name in cls and its base classes."
if cls.__dict__.has_key(name):
return cls.__dict__[name]
for base in cls.__bases__:
try:
return classic_lookup(base, name)
except AttributeError:
pass
raise AttributeError, name
In Python 2.2, I've decided to adopt a different lookup rule for new-style classes. (The rule for classic classes remains unchanged for backwards compatibility considerations; eventually all classes will be new-style classes and then the distinction will go away.) I'll try to explain what's wrong with the classic rule first.
The problem with the classic rule becomes apparent when we consider a "diamond diagram":
class A:
^ ^ def save(self): ...
/ \
/ \
/ \
/ \
class B class C:
^ ^ def save(self): ...
\ /
\ /
\ /
\ /
class D
Arrows point from a subtype to its base type(s). This particular diagram means B and C derive from A, and D derives from B and C (and hence also, indirectly, from A).
Assume that C overrides the method save(), which is defined in the base A. (C.save() probably calls A.save() and then saves some of its own state.) B and D don't override save(). When we invoke save() on a D instance, which method is called? According to the classic lookup rule, A.save() is called, ignoring C.save()!
This is not good. It probably breaks C (its state doesn't get saved), defeating the whole purpose of inheriting from C in the first place.
Why wasn't this a problem in classic Python? Diamond diagrams are rarely found in classic Python class hierarchies. Most class hierarchies use single inheritance, and multiple inheritance is usually limited to mix-in classes. In fact, the problem shown here is probably the reason why multiple inheritance is unpopular in classic Python!
Why will this be a problem in the new system? The 'object' type at the top of the type hierarchy defines a number of methods that can usefully be extended by subtypes, for example __getattribute__() and __setattr__().
(Aside: the __getattr__() method is not really the implementation for the get-attribute operation; it is a hook that only gets invoked when an attribute cannot be found by normal means. This has often been cited as a shortcoming - some class designs have a legitimate need for a get-attribute method that gets called for all attribute references, and this problem is solved now by making __getattribute__() available. But then this method has to be able to invoke the default implementation somehow. The most natural way is to make the default implementation available as object.__getattribute__(self, name).)
Thus, a classic class hierarchy like this:
class B class C:
^ ^ __setattr__()
\ /
\ /
\ /
\ /
class D
will change into a diamond diagram under the new system:
object:
^ ^ __setattr__()
/ \
/ \
/ \
/ \
class B class C:
^ ^ __setattr__()
\ /
\ /
\ /
\ /
class D
and while in the original diagram C.__setattr__() is invoked, under the new system with the classic lookup rule, object.__setattr__() would be invoked!
Fortunately, there's a lookup rule that's better. It's a bit difficult to explain, but it does the right thing in the diamond diagram, and it is the same as the classic lookup rule when there are no diamonds in the inheritance graph (when it is a tree).
The new lookup rule constructs a list of all classes in the inheritance diagram in the order in which they will be searched. This construction is done when the class is defined, to save time. To explain the new lookup rule, let's first consider what such a list would look like for the classic lookup rule. Note that in the presence of diamonds the classic lookup visits some classes multiple times. For example, in the ABCD diamond diagram above, the classic lookup rule visits the classes in this order:
D, B, A, C, A
Note how A occurs twice in the list. The second occurrence is redundant, since anything that could be found there would already have been found when searching the first occurrence. But it is visited nonetheless (the recursive implementation of the classic rule doesn't remember which classes it has already visited).
We use this observation to explain our new lookup rule. Using the classic lookup rule, construct the list of classes that would be searched, including duplicates. Now for each class that occurs in the list multiple times, remove all occurrences except for the last. The resulting list contains each ancestor class exactly once (including the most derived class, D in the example): D, B, C, A.
Searching for methods in this order will do the right thing for the diamond diagram. Because of the way the list is constructed, it never changes the search order in situations where no diamond is involved.
Isn't this backwards incompatible? Won't it break existing code? It would, if we changed the method resolution order for all classes. However, in Python 2.2, the new lookup rule will only be applied to types derived from built-in types, which is a new feature. Class statements without a base class create "classic classes", and so do class statements whose base classes are themselves classic classes. For classic classes the classic lookup rule will be used. We may also provide a tool that analyzes a class hierarchy looking for methods that would be affected by a change in method resolution order.
Reference:
Method resolution order
References for super and MRO:
python-201-what-is-super
Super-object-usage-explanationInheritance Versus Composition
Here is an interesting write up on not to use a class to raise an exception:
Inherit from BaseException for all custom exceptions
Description
Classes used for handling and representing exceptions must always inherit from BaseException at the lowest level. User-defined exception classes should actually inherit from Exception; they shouldn't directly inherit from BaseException. Python requires all exception classes to inherit from a base exception superclass to ensure that they all meet the minimum required interface needed to be useful.
Anti-pattern
The module below defines a class MyException and then attempts to raise this as an exception. Python raises a TypeError when it encounters this code because all classes raised as exceptions must inherit from BaseException.
class MyException(object):
def __init__(self, code, message):
self.code = code
self.message = message
try:
if 1 != 0:
raise MyException(42, "1 != 0 Exception")
except MyException as e:
print(e.message)
Best practices
Modify the class to inherit from BaseException
In the modified module below, the user-defined exception class has been modified to inherit from BaseException. The class actually inherits from Exception, which in turn inherits from BaseException. User-defined exception classes should never inherit directly from BaseException.
class MyException(Exception):
def __init__(self, code, message):
self.code = code
self.message = message
try:
if 1 != 0:
raise MyException(1244, "1 != 0 Exception")
except MyException as e:
print(e.message)
Do not raise the class as an exception
If the raised class cannot be modified, then the class should not be raised to handle exceptions. In the modified module below the module now raises Exception instead of MyException.
try:
if 1 != 0:
raise Exception("Exception: 1 != 0")
except Exception as e:
print(e)
References
What is __iter__() and how to use it:
Iterator objects in python conform to the iterator protocol, which basically means they provide two methods: __iter__() and next(). The __iter__ returns the iterator object and is implicitly called at the start of loops. The next() method returns the next value and is implicitly called at each loop increment. next() raises a StopIteration exception when there are no more value to return, which is implicitly captured by looping constructs to stop iterating.
Examples of using iter:
class Counter:
def __init__(self, low, high):
self.current = low
self.high = high
def __iter__(self):
return self
def next(self): # Python 3: def __next__(self)
if self.current > self.high:
raise StopIteration
else:
self.current += 1
return self.current - 1
for c in Counter(3, 8):
print c
This will Print:
3
4
5
6
7
8
Another method that is straight forward:
def counter(low, high):
current = low
while current <= high:
yield current
current += 1
for c in counter(3, 8):
print c
References: l-pycon & build a basic python iterator
Using Python to print color in terminal (Linux):
Many computer terminals and terminal emulators support colour and cursor control through a system of escape sequences. One such standard is commonly referred to as ANSI Colour. Several terminal specifications are based on the ANSI colour standard, including VT100.
The following is a partial listing of the VT100 control set.
<ESC> represents the ASCII "escape" character, 0x1B. Bracketed tags represent modifiable decimal parameters; eg. {ROW} would be replaced by a row number.
The following codes are used for reporting terminal/display settings, and vary depending on the implementation:Query Device Code <ESC>[c
- Requests a
Report Device Code response from the device.
Report Device Code <ESC>[{code}0c
- Generated by the device in response to
Query Device Code request.
Query Device Status <ESC>[5n
- Requests a
Report Device Status response from the device.
Report Device OK <ESC>[0n
- Generated by the device in response to a
Query Device Status request; indicates that device is functioning correctly.
Report Device Failure <ESC>[3n
- Generated by the device in response to a
Query Device Status request; indicates that device is functioning improperly.
Query Cursor Position <ESC>[6n
- Requests a
Report Cursor Position response from the device.
Report Cursor Position <ESC>[{ROW};{COLUMN}R
- Generated by the device in response to a
Query Cursor Position request; reports current cursor position.
The h and l codes are used for setting terminal/display mode, and vary depending on the implementation. Line Wrap is one of the few setup codes that tend to be used consistently:
Reset Device <ESC>c
- Reset all terminal settings to default.
Enable Line Wrap <ESC>[7h
- Text wraps to next line if longer than the length of the display area.
Disable Line Wrap <ESC>[7l
Some terminals support multiple fonts: normal/bold, swiss/italic, etc. There are a variety of special codes for certain terminals; the following are fairly standard:
Font Set G0 <ESC>(
Font Set G1 <ESC>)
Cursor Home <ESC>[{ROW};{COLUMN}H
- Sets the cursor position where subsequent text will begin. If no row/column parameters are provided (ie.
<ESC>[H), the cursor will move to the home position, at the upper left of the screen.
Cursor Up <ESC>[{COUNT}A
- Moves the cursor up by COUNT rows; the default count is 1.
Cursor Down <ESC>[{COUNT}B
- Moves the cursor down by COUNT rows; the default count is 1.
Cursor Forward <ESC>[{COUNT}C
- Moves the cursor forward by COUNT columns; the default count is 1.
Cursor Backward <ESC>[{COUNT}D
- Moves the cursor backward by COUNT columns; the default count is 1.
Force Cursor Position <ESC>[{ROW};{COLUMN}f
- Identical to
Cursor Home.
Save Cursor <ESC>[s
- Save current cursor position.
Unsave Cursor <ESC>[u
- Restores cursor position after a
Save Cursor.
Save Cursor & Attrs <ESC>7
- Save current cursor position.
Restore Cursor & Attrs <ESC>8
- Restores cursor position after a
Save Cursor.
Scroll Screen <ESC>[r
- Enable scrolling for entire display.
Scroll Screen <ESC>[{start};{end}r
- Enable scrolling from row
{start} to row {end}.
Scroll Down <ESC>D
- Scroll display down one line.
Scroll Up <ESC>M
- Scroll display up one line.
Set Tab <ESC>H
- Sets a tab at the current position.
Clear Tab <ESC>[g
- Clears tab at the current position.
Clear All Tabs <ESC>[3g
Erase End of Line <ESC>[K
- Erases from the current cursor position to the end of the current line.
Erase Start of Line <ESC>[1K
- Erases from the current cursor position to the start of the current line.
Erase Line <ESC>[2K
- Erases the entire current line.
Erase Down <ESC>[J
- Erases the screen from the current line down to the bottom of the screen.
Erase Up <ESC>[1J
- Erases the screen from the current line up to the top of the screen.
Erase Screen <ESC>[2J
- Erases the screen with the background colour and moves the cursor to home.
Some terminals support local printing:Print Screen <ESC>[i
- Print the current screen.
Print Line <ESC>[1i
Stop Print Log <ESC>[4i
Start Print Log <ESC>[5i
- Start log; all received text is echoed to a printer.
Set Key Definition <ESC>[{key};"{string}"p
- Associates a string of text to a keyboard key.
{key} indicates the key by its ASCII value in decimal.
Set Attribute Mode <ESC>[{attr1};...;{attrn}m
Reference: http://www.termsys.demon.co.uk/vtansi.htm and terminalcodes
Slicing through a string
>>> 'abcdefghij'[2:5]
'cde'
>>> 'abcdefghij'[:3]
'abc'
>>> 'abcdefghij'[3:]
'defghij'
2:5 means to start to slice at 2