In [8]:
class Dog:
def __init__(self, name):
self.age = 0
self.name = name
self.noise = "Woof!"
self.food = "dog biscuits"
def make_sound(self):
print(self.noise)
def eat_food(self):
print("Eating " + self.food + ".")
def increase_age(self, n = 1):
self.age = self.age + n
d1 = Dog('Buster')
d1.make_sound()
d2 = Dog('Tiger')
d2.noise = 'Bark'
d2.make_sound()
d1.make_sound()
d1.eat_food()
d1.increase_age(3)
print(d1.age)
In [9]:
class Cat:
def __init__(self, name):
self.age = 0
self.name = name
self.noise = "Meow!"
self.food = "cat food"
def make_sound(self):
print(self.noise)
def eat_food(self):
print("Eating " + self.food + ".")
def increase_age(self, n = 1):
self.age = self.age + n
c1 = Cat('Harvey')
c1.make_sound()
c1.eat_food()
In the above examples, it becomes clear that there is much repetition, and we can make the code more compact. Let us abstract common functionality into an abstract class.
In [3]:
from abc import ABCMeta, abstractmethod
class Mammal(metaclass=ABCMeta):
@abstractmethod
def __init__(self, name):
self.age = 0
self.name = name
self.noise = "None!"
self.food = "none"
def make_sound(self):
print(self.name + " says " + self.noise)
def eat_food(self):
print(self.name + " is eating " + self.food + ".")
def increase_age(self, n = 1):
self.age = self.age + n
class Dog(Mammal):
def __init__(self, name):
super(Dog, self).__init__(name)
self.noise = "Bark!"
self.food = "dog biscuits"
class Cat(Mammal):
def __init__(self, name):
super(Cat, self).__init__(name)
self.noise = "Meow!"
self.food = "cat food"
d = Dog("Buster")
c = Cat("Harvey")
d.make_sound()
c.make_sound()
c.eat_food()
m = Mammal("Name")
m.make_sound()
m.eat_food()
import sys
print(sys.version)
In [23]:
animal_house = [Dog("MyDog" + str(i))
for i in range(1, 5)]
animal_house.extend([Cat("MyCat" + str(i))
for i in range(1, 5)])
for i in animal_house:
i.make_sound()
In [40]:
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def next(self): # def next(self): in Python 2!
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
rev = iter(Reverse([10, 30, 200, 0.0, 'ABC']))
for i in rev:
print(i)
In [31]:
def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
for char in reverse("Madam, I'm Adam"):
print(char)
In [3]:
import math
def series_sum(max_terms=1000):
n = 0
while n < max_terms:
n = n + 1
yield 1.0 / n**2
print(sum(series_sum(100000)) - math.pi**2 / 6)
The key thing to note is that this is much more efficient than generating a list of terms in memory and summing it. That is, more efficient than
In [5]:
print(sum([1.0 / i**2 for i in range(1, 10000)]))
In [51]:
def add_numbers(a, b):
return a + b
def arg_wrapper(f, *args, **kwargs):
print("The function arguments are:")
print(args)
print(kwargs)
print("Now running the function!")
return f(*args, **kwargs)
#print(add_numbers(1, 2))
#print(arg_wrapper(add_numbers, 1, 2))
def myfunction(name='Test', age=30):
print("Name: %s, Age: %d" % (name, age))
arg_wrapper(myfunction, name='Harvey', age=3)
In [57]:
import time
def timing_function(some_function):
def wrapper():
t1 = time.time()
some_function()
t2 = time.time()
return "Time it took to run the function: " + str((t2 - t1)) + "\n"
return wrapper
@timing_function
def my_function():
num_list = []
for num in (range(0, 10000)):
num_list.append(num)
print("\nSum of all the numbers: " + str((sum(num_list))))
my_function()
Out[57]: