# Difference between __str__() and __repr__()

In Python, a class has 2 methods that can return a string representation, __str__() and __repr__().

__str__() is called by the format() and print() functions. It should return a nicely printable representation of the object.
The default implemntation of __str__() in class object just calls __repr__().

__repr__() is meant for debuggers, and should return an informative and unambiguous representation of the object. Ideally, it should take the form of a valid Python expression, such as a constructor call, that can be used to reconstruct the object. You can see this representation by using the built-in repr() function on an object.

# super() in Python

The primary purpose of super() in Python is to call an overridden base class method in a derived class, as super does in other languages.
This is usually done so that a derived class method can augment a base class one by calling it before or after its own code, rather than completely replacing it.

class Derived(Base):
def method(self, arg):
# Maybe do something here
super(Derived, self).method(arg)
# Could so something here as well


The super() function actually works by returning an object of a proxy class that delegates calls to the parent.
The advantage of using super() in this case is that you don’t need to explicitly name the base class, which aids maintainability.

The super() function can also be used in more complex multiple inheritance situations, where it can do things like delegate to a sister class.
These uses of super are described in Python’s super() considered super!.

# Enums in Python

Enums have been added to Python 3.4 with PEP 435. They have also been backported to versions 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4 with enum34.

To declare an enum, declare a subclass of enum.Enum:

from enum import Enum

class Colour(Enum):
red = 1
yellow = 2
blue = 3


You can access the enumerated values (and names) in the following ways:

>>> Colour.red
<Colour.red: 1>
>>> Colour['red']
<Colour.red: 1>
>>> Colour(1)
<Colour.red: 1>
>>> Colour.red.name
'red'
>>> Colour.red.value
1


You can also treat the enumeration as an iterable:

>>> for colour in Colour:
...     print colour
...
Colour.red
Colour.yellow
Colour.blue
>>> len(Colour)
3


# Finding a substring in Python

You can simply use in to find out if a string contains another string:

line = "A license for my pet fish, Eric."


Use find() to get the position of the substring:

pos = line.find('license')
if pos != -1:
print '"license" starts at position {0} of line'.format(pos)


# Accessing the loop index in Python

You can get access to the loop index in Python by using the enumerate() function to loop over your iterable:

for index, value in enumerate(['spam', 'eggs', 'ham']):
print index, value


# Difference between append and extend in Python

append() adds an item at the end.
extend() adds the contents of an iterable at the end.

def main():
dishes = ['spam', 'eggs']
dishes.append('ham')
print dishes
dishes.extend(['spam', 'spam', 'spam'])
print dishes


This prints:

['spam', 'eggs', 'ham']
['spam', 'eggs', 'ham', 'spam', 'spam', 'spam']


# Pass by reference in Python

There is no pass by reference in Python, so it isn’t possible to pass an variable to a function and have it assigned a new value within the function, including passing in an immutable primitive type value and having it replaced with a modified value.

It is possible to do something similar though by passing in the value inside a data structure or other object.

For example, in the following program a string has its value modified in two different ways. Firstly, a class object is used to store the string’s value, and secondly, a list is used for the same purpose.

class Wrapper(object):
def __init__(self, value):
self.value = value

def pass_by_reference1(wrapper):
wrapper.value = wrapper.value + ", and spam"

def pass_by_reference2(wrapper):
wrapper[0] = wrapper[0] + ", and spam"

def main():
var1 = Wrapper("A string");
pass_by_reference1(var1)
print var1.value

var2 = ["Another string"]
pass_by_reference2(var2)
print var2[0]

if __name__ == '__main__':
main()


# Mutable default arguments

Python primitive types are immutable. Objects though, including lists and dictionaries are mutable.
This can cause a problem when they’re used as the default argument to a function.

Consider the following code:

def append(item, dest=[]):
dest.append(item)
return dest

def main():
order1 = append('spam')
print order1
order2 = append('eggs')
print order2

if __name__ == '__main__':
main()


You would think that this code would print:

['spam']
['eggs']


In fact it prints:

['spam']
['spam', 'eggs']


This is because the default argument, rather than being evaluated every time the function is called, is evaluated just once when the function definition is compiled.

The way to get the expected behaviour is to rewrite the function as follows:

def append(item, dest=None):
if dest is None:
dest = []
dest.append(item)
return dest


# Difference between a @staticmethod and a @classmethod

## @staticmethod

A @staticmethod can only be called from a class or an instance, but does not take a class or instance as its first argument.
So a @staticmethod is a helper function that is specific enough that it should belong to the class, but does not need access to the class or object.

## @classmethod

A @classmethod can be called from a class or an instance and takes the class as its first argument.
You most commonly use a @classmethod to provide an alternative method of object construction (a Factory Method).

# Checking if a Python list is empty

if not a:
print "List is empty"


Reference: Programming Recommendations