In [17]:
import time
t = time.localtime()
t.tm_mday
Out[17]:
Python has a very active development community and the Python package index contains a myriad of packages for every need.
These can be install by using pip
which is installed with newer python versions:
pip install numpy
In [18]:
class Dog(object):
color = "yellow"
def __init__(self, name):
self.name = name
Dog
Out[18]:
In [19]:
class Dog(object):
color = "yellow"
def __init__(self, name, size):
self.name = name
self.size = size
def bark(self):
print 'whoof, whoof!'
b = Dog("blitzer", 100)
b.bark()
In [20]:
class Dachshund(Dog):
color = "brownish"
def __init__(self, name):
super(Dachshund, self).__init__(name, 20)
d = Dachshund('bello')
d.bark()
In [21]:
class Pekingese(Dog):
color = "brownish"
def __init__(self, name):
super(Pekingese, self).__init__(name, 15)
def bark(self):
print 'whif.'
d = Pekingese('tiny')
d.bark()
In [78]:
class Pekingese(Dog):
color = "brownish"
def __init__(self, name):
super(Pekingese, self).__init__(name, 15)
def __len__(self):
return self.size
def bark(self):
print 'whif.'
In [79]:
p = Pekingese("wang")
len(p)
Out[79]:
In [77]:
class Dog(object):
color = "yellow"
def __init__(self, name, size):
self.name = name
self.size = size
def __add__(self, dog):
if not isinstance(dog, Dog):
raise TypeError
return Dog(self.name + " " + dog.name, (self.size + dog.size)/2)
def bark(self):
print 'whoof, whoof!'
In [89]:
b = Dog("blitzer", 100)
dog = b + p
dog.bark()
print dog.name
print dog.size
In [22]:
def outer_function():
print "out here"
def inner_1():
return "in room 1"
def inner_2():
return "in room 2"
print inner_1()
print inner_2()
outer_function()
In [23]:
def greetings(some_function):
def wrapper(args):
print "Hello!"
some_function(args)
print "Goodbye!"
return wrapper
def say_something(sentence):
print "Say: {0}".format(sentence)
In [24]:
polite_talker = greetings(say_something)
polite_talker("Good to see you")
In [25]:
@greetings
def shout(sentence):
print sentence.upper()
In [26]:
shout("Am I polite, or what?!")
In [27]:
class Molecule(object):
def __init__(self, mass):
self.mass = mass
@property
def mass(self):
return self.__mass
@mass.setter
def mass(self, value):
if not isinstance(value, int):
raise TypeError("Mass must be Integer.")
self.__mass = value
In [28]:
m = Molecule(1)
In [29]:
m.mass = "two"
As you might know you can assign values of one variable to an other like:
In [30]:
A = [5]
B = A
print B
But if you change the value of variable A as it is done blow, variable B changes, too.
In [31]:
A[0] = 1
print B
The problem is that variables are just names referring to an object. Assigning the object of a variable to an other does not create a copy of this object. It creates a new variable B which refers to the same object A refers to. Hence, there is only one object but two variables are referring to this one. This holds only for mutable objects like lists, sets, dictionaries and so on.
There are also immutable objects like inits, floats, strings, tuple and so on.
In [32]:
A = 1
B = A
A += 1
print B
The difference in this example is, that we are not incrementing the value of A, but instead we are creating a new object and assigning this new object to our variable A. After this we have two objects the Integer 1 and the Integer 2 and two variables B and A referring to the objects, respectively.
Some operations change the object instead creating a copy of the object assigned to a variable.
In [33]:
A = [[2,3,1]]
B = A
A[0].append(4)
print B
A[0].sort()
print B
However, some operations directly create new objects.
In [34]:
A = [[2,3,1]]
B = A
A = A + [4]
print B
print sorted(A[0])
print B
So we end up with two objects and two variables referring to these objects, respectively.
But we have to pay attention when we use operations like +=. The behaviour of this kind of operations depends on the object it is applied on.
In [35]:
A = ((1,2,3)) # assigning a immutable tuple object to A
B = A
A += (3,4,5)
print "A: ", A
print "B: ", B
If we apply this operation on a variable referring to an immutable object - a new object is created, but if we apply this to an object referring to a mutable object like lists, sets and so on we are just changing the object.
In [36]:
A = [1,2,3] # assigning a mutable list object to A
B = A
A += [1]
print "A: ", A
print "B: ", B
In this case the += operation on a list is equivalent to the A.extend([1]) operation.
The copy operation can be used to make copies of an object. Like
In [37]:
import copy
A = [5]
B = copy.copy(A)
A[0] = 1
print "A: ", A
print "B: ", B
The copy operation creates a copy of the object (in this case a list) assigned to variable A and set references of the inner objects. The inner object (integer 1) is immutable, hence, the variable B will not change if we change A. But if we have something like
In [38]:
A = [[5]]
B = copy.copy(A)
A[0][0] = 1
print "A: ", A
print "B: ", B
We will change variable B if we change the inner object of variable A. This is because we have a copy of the first object (outer list) and just set a reference of the inner object. This brings us back to the problem we discussed above.
To avoid this we have the possibility to make a deepcopy of our object assigned to a variable.
In [39]:
import copy
A = [[5]]
B = copy.deepcopy(A)
A[0][0] = 1
print "A: ", A
print "B: ", B
With this operation we are creating a new object of the first object and for all nested objects, too. This means that the entire structure is copied and we end up with two objects (containing arbitray nested objects) assigned to two variables.
In [40]:
A = [1, 2, 3]
B = ['a', 'b', 'c']
z = zip(A, B)
print "zipping: ", z
print "unzipping: ", zip(*z)
In [41]:
# dictionary comprehension
name_space = "a","b","c","d","e"
dictionary = {name_space[x]: x**2 for x in range(len(name_space))}
print "dictionary comprehension: ", dictionary
In [42]:
# creating a dictionary using zip function
dictionary = dict(zip(['A', 'B', 'C'], [1, 2, 3]))
print "dictionary: ", dictionary
In [43]:
# default dictionary
from collections import defaultdict
default_dict = defaultdict(int)
default_dict['a'] += 1 # increasing the value of key "a" directly during the initialisation of the key
print "default dictionary: ", default_dict
# normal dictionary initialisation
no_default = dict()
no_default['a'] += 1
In [44]:
dictionary = dict(a=1, b=2, c=3) # normal dict generation
print "dictionary: ", dictionary
# inverting dictionary using zip function
inverted_dict = dict(zip(dictionary.values(), dictionary.keys()))
print "inverted dict: ", inverted_dict
In [45]:
from collections import OrderedDict
ordered_dict = OrderedDict((name_space[x], x**2) for x in range(len(name_space)))
print "ordered dictionary: ", ordered_dict
In [46]:
import itertools
def k_mer(word, size):
z = (itertools.islice(word, i, None) for i in range(size))
return zip(*z)
string = "HelloWorld"
k_mer(string,3)
Out[46]:
In [47]:
import itertools
for p in itertools.permutations([1,2,3]):
print "permutations: ", p
In [48]:
import itertools
a_list = [[1,2],[3,4],[5,6]]
a_flatted_list = [x for i in a_list for x in i]
print "a_flatted_list: ", a_flatted_list