Sep 25-27, 2019 Vikrant Patil
These notes are available online at http://notes.pipal.in/2019/arcesium_advanced_sep/day3.html
© Pipal Academy LLP
Notebooks available at git repository https://github.com/vikipedia/advpythonsep19.git
We will be using python 3 (>= 3.0) from anaconda for this training. You can download it from
%%file bank.py
def make_account():
return {"balance":0}
def get_balance(account):
return account['balance']
def withdraw(account, amount):
account['balance'] -= amount
def deposit(account, amount):
account['balance'] += amount
import bank
a1 = bank.make_account()
bank.get_balance(a1)
bank.deposit(a1, 1000)
bank.withdraw(a1, 343)
bank.get_balance(a1)
a1['balance'] = 4545
class BankAccount:
def __init__(self):
self.balance = 0
def get_balance(self):
return self.balance
def withdraw(self, amount):
self.balance -= amount
def deposit(self, amount):
self.balance += amount
a = BankAccount()
class BankAccount:
def __init__(self, accountno, balance):
self.balance = balance
self.accountno = accountno
def get_balance(self):
return self.balance
def withdraw(self, amount):
self.balance -= amount
def deposit(self, amount):
self.balance += amount
a2 = BankAccount(42, 0)
a2.get_balance()
a2.deposit(5000)
a2.withdraw(2323)
a2.get_balance()
BankAccount
a2
BankAccount.get_balance
a2.get_balance
type(a2)
type(BankAccount)
BankAccount.get_balance()
BankAccount.get_balance(a2)
a2.get_balance
a2.get_balance(a2)
x = 10
def foo():
print(x)
foo()
x = 10
def foo():
x = 20
print(x)
x = 10
def foo():
print(x)
x = 15
foo()
x = 10
def foo():
global x
print(x)
x = 15
foo()
class Foo:
name = "bar"
def __init__(self, x):
self.x = x
f1 = Foo(5)
f2 = Foo(10)
f1.name
f2.name
Foo.name
Foo.name = "foo"
f1.name
f2.name
f1.name = "xyz"
Foo.name
f2.name
f1.name
class Bar:
b = 10
def changeg(self, x):
global b
b = x
def chnagewithaccess(self, x):
print(b)
b = x
b = Bar()
b.changeg(50)
Bar.b
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
Point(2,3)
[1,2,3]
Point
type(Point)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
"""
This will shown when you examine object
from interpreter
"""
return "Point({},{})".format(self.x, self.y)
def __str__(self):
"""
This string is shown when you print the object
"""
return "({}, {})".format(self.x, self.y)
p = Point(2,3)
p
print(p)
str(p)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
"""
This will shown when you examine object
from interpreter
"""
return "Point({},{})".format(self.x, self.y)
def __str__(self):
"""
This string is shown when you print the object
"""
return "({0.x!s}, {0.y!s})".format(self)
def __len__(self):
return 2
p = Point(3,5)
print(p)
len(p)
Point.__add__ = lambda self, p: Point(self.x+p.x, self.y+p.y)
Point(2,3) + Point(1,1)
problem
Write a class to represnt complex number. Support proper printing and following operators
+ -> __add__(self, c):- -> __sub__(self, c):== -> __eq__(self, c):[] -> __getitem__(self, name):d = {"a":1}
d['b']
d['a']
class mydictionary:
def __init__(self):
self.keys = []
self.values = []
def __setitem__(self, name, value):
if name in self.keys:
ind = self.keys.index(name)
self.values[ind] = value
else:
self.keys.append(name)
self.values.append(value)
def __getitem__(self, name):
if name in self.keys:
ind = self.keys.index(name)
return self.values[ind]
raise KeyError("No such key, {}!".format(name))
d = mydictionary()
d['x'] = 1
d['x']
d['y']
Where is object data stored?
p
type(p)
p.x
p.y
p.__dict__
p.z = 30
p.z
p.__dict__
import time
class Timer:
def start(self):
self._start = time.time()
def stop(self):
self._stop = time.time()
def time_taken(self):
return self._end - self._start
t = Timer()
class Timer:
def __init__(self):
self._start = 0
self._stop = 0
def start(self):
self._start = time.time()
def stop(self):
self._stop = time.time()
def time_taken(self):
return self._end - self._start
d['x']
p.s = 5
class Sealed:
def __setattr__(self, key, value):
raise Exception("No chance!")
s = Sealed()
s.x = 12
problem
p = Point(3, 4)
p.x =45 <== should throw exception
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __setattr__(self, key, value):
raise Exception("No chance!")
Point(3, 4)
class Point:
def __init__(self, x, y):
self.__dict__['x'] = x
self.__dict__['y'] = y
def __setattr__(self, key, value):
raise Exception("No chance!")
p = Point(3,4)
p.x = 34
class Point:
def __init__(self, x, y):
self.init = True
self.x = x
self.y = y
def __setattr__(self, key, value):
if self.init and key in ['x','y']:
self.init = False
self.__dict__[key] = value
else:
raise Exception("No chance!")
p = Point(3, 4)
class Upper:
def __getattr__(self, key):
return key.upper()
u = Upper()
u.hello
class Point:
pass
class ColoredPoint(Point):
pass
class A:
pass
class B:
pass
class C(A,B):
pass
C.__mro__
class A:
def __init__(self):
print("A.__init__")
class B(A):
def __init__(self):
print("B.__init__")
A.__init__(self)
class C(B):
def __init__(self):
print("C.__init__")
B.__init__(self)
class D(C,B):
def __init__(self):
print("D.__init__")
C.__init__(self)
B.__init__(self)
D()
class A:
def __init__(self):
print("A.__init__")
class B(A):
def __init__(self):
print("B.__init__")
super().__init__()
class C(B):
def __init__(self):
print("C.__init__")
super().__init__()
class D(C,B):
def __init__(self):
print("D.__init__")
super().__init__()
D()
class Date:
__slots__ = ['year', 'month', 'day']
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
d = Date(2017, 4, 21)
d.x = 50
type(Point)
type(Date)
class Meta(type):
pass
class SubMetaClass(Meta):
pass
SubMetaClass()
Meta()
class SubMetaClass1(metaclass=Meta):
pass
type(SubMetaClass1)
type(Meta)
type(SubMetaClass)
class Singleton(type):
def __init__(self, *args, **kwargs):
print(args)
print(kwargs)
self._instance = None
def __call__(self, *args, **kwargs):
if self._instance:
return self._instance
else:
self._instance = super().__call__(*args, **kwargs)
return self._instance
class SingletonTop(metaclass=Singleton):
pass
class X(SingletonTop):
pass
x = X()
y = X()
x == y
id(x)
id(y)
p1 = Point()
p2 = Point()
id(p1), id(p2)
p1 is p2
x is y
l1 = [1,2,3]
l2 = [1,2,3]
l1 == l2
l1 is l2
p1 == p2
p1 == p1
class Shape:
def contains(self, point):
pass
from abc import ABCMeta, abstractmethod
class Shape(metaclass=ABCMeta):
@abstractmethod
def contains(self, point):
pass
class Circle(Shape):
pass
Circle()
class ShapeArea:
def area(self):
pass
class Circle(ShapeArea):
def area(self):
pass
class Square(ShapeArea):
pass
class Rectangle:
pass
shapes = [Circle(), Square() , Rectangle()]
for s in shapes:
s.area()
class Person:
def __init__(self, name):
self.name = name
@property
def email(self):
return "@".join([self.name, "arcesium.com"])
@email.setter
def email(self, value):
raise Exception("You can not change email")
p = Person("praveen")
p.email
p.email = "pravin@arcesium.com"
class Person1:
def __init__(self, name):
self.name = name
@property
def email(self):
return "@".join([self.name, "arcesium.com"])
p1 = Person1("hello")
p1.email
p1.email = "xyz@lskd;as"
from functools import wraps, partial
def debug(func):
prefix = "*"*5
msg = prefix + func.__qualname__
@wraps(func)
def wrapper(*args, **kwargs):
print(msg)
return func(*args, **kwargs)
return wrapper
def debugmethods(cls):
for name, val in vars(cls).items():
if callable(val):
setattr(cls, name, debug(val))
return cls
@debugmethods
class FooBar:
x = "hello"
def method1(self):
pass
def method2(self):
pass
def method3(self):
pass
fb = FooBar()
fb.x
fb.method1()
fb.method2()
class Integer:
def __init__(self, name):
self.name = name
def __get__(self, instance, cls):
print("__get__ from", self)
if instance is None:
return self
else:
return instance.__dict__[self.name]
def __set__(self, instance, value):
print("__set__ from", self)
if not isinstance(value, int):
raise TyepeError("Expected int")
instance.__dict__[self.name] = value
def __delete__(self, instance):
print("__del__ from", self)
del instance.__dict__[self.name]
def __str__(self):
return "Integer<{0.name!s}>".format(self)
class Point:
x = Integer('x')
y = Integer('y')
def __init__(self, x, y):
self.x = x
self.y = y
def __setattr__(self, name, value):
print("__setattr__ of Point")
super().__setattr__(name, value)
p = Point(2,3)
p.x
p.y
p.x = 5
p.z = 5
1
1
1
class my_property:
def __init__(self, func):
self.func = func
def __get__(self, instance, cls):
if instance is None:
return self
print("my_property.__get__")
return self.func(instance)
class Person:
def __init__(self, name):
self.name = name
@my_property
def email(self):
return "@".join([name, "gmail.com"])
class MyInt:
def __init__(self, strnum):
self.value = int(strnum)
def parse(strnum):
return int(strnum)
MyInt.parse("454")
m = MyInt("34")
m.parse("4")
class MyInt:
def __init__(self, strnum):
self.value = int(strnum)
@staticmethod
def parse(strnum):
return int(strnum)
m = MyInt("67")
m.parse("45")
import datetime
class MyDatetime(datetime.datetime):
pass
datetime.datetime.now()
MyDatetime.now()
class Foo:
def __init__(self, x):
self.x = x
def __repr__(self):
return "{}({})".format(self.__class__.__name__, repr(self.x))
@classmethod
def instance(cls, value):
return cls(value)
@staticmethod
def instance1(value):
return Foo(value)
class Bar(Foo):
pass
Bar.instance1(3)
Bar.instance(5)
with open("data.csv") as f:
f.read()
class Timer:
def __init__(self):
self._start = 0
self._stop = 0
def start(self):
self._start = time.time()
def stop(self):
self._stop = time.time()
def time_taken(self):
return self._stop - self._start
class ContextTimer(Timer):
def reset(self):
self._start = 0
self._stop = 0
def __enter__(self):
print("Beging with block ....")
self.reset()
self.start()
print("Now entering...")
return self
def __exit__(self, exc_type, exc_value, traceback):
self.stop()
print(exc_type, exc_value, traceback)
print("Time taken in with block: ", self.time_taken())
ct = ContextTimer()
with ct:
print("Inside with body....")
for i in range(10000):
for j in range(10000):
s = i*j*1.0
print("End of with body...")
ct = ContextTimer()
with ct:
print("Inside with body....")
for i in range(10000):
for j in range(10000):
s = i*j*1.0
boom
print("End of with body...")
import threading
def tick(n):
for i in range(n):
print("Tick-", i)
time.sleep(1)
def reversetick(n):
for i in reversed(range(n)):
print("Tick-down-", i)
time.sleep(1)
t1 = threading.Thread(target=tick, args=(10,))
t2 = threading.Thread(target=reversetick, args=(10,))
t1.start()
t2.start()
t1.join()
t2.join()
print("Tasks are over")
event = threading.Event()
def tick(event):
i = 0
while not event.isSet():
print("Tick-", i)
time.sleep(2)
i += 1
t = threading.Thread(target=tick, args=(event,))
t.start()
event.set()
import random
def producer(data, lock, event):
while not event.isSet():
with lock:
data.append(random.choice([0,1]))
print("Produced...", data[-1])
time.sleep(1)
def consumer(data, lock, event):
while not event.isSet():
with lock:
print("Consumed...", data.pop())
time.sleep(1)
def observer(data, lock, event):
while not event.isSet():
print(data)
time.sleep(1)
data = list(range(5))
lock = threading.Lock()
event = threading.Event()
p = threading.Thread(target=producer, args=(data, lock, event))
c = threading.Thread(target=consumer, args=(data, lock, event))
o = threading.Thread(target=observer, args=(data, lock, event))
o.start()
p.start()
time.sleep(3)
c.start()
event.set()
x , y, z = 1, 2, 3
from multiprocessing.pool import ThreadPool
pool = ThreadPool(4)
import requests
def download(url):
resp = requests.get(url)
return resp
def threaded_download(n):
pool = ThreadPool(n)
url = "https://ia802902.us.archive.org/4/items/prideandprejudic01342gut/pandp12.txt"
urls = [url]*10
res = pool.map(download, urls)
return res
for i in range(1,9):
with ContextTimer() as t:
threaded_download(i)
from multiprocessing.pool import Pool
class ContextTimer(Timer):
def reset(self):
self._start = 0
self._stop = 0
def __enter__(self):
self.reset()
self.start()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.stop()
print("Time taken in with block: ", self.time_taken())
def saxpy(n):
s = 0
for i in range(n):
for j in range(n//10):
s += 1*j*1.0
return s
def process_pool(n):
pool = Pool(n)
args = [10000]*10
res = pool.map(saxpy, args)
return res
for i in range(1,9):
with ContextTimer() as t:
process_pool(i)
%load_ext Cython
%%cython --annotate
def square(x):
return x*x
def sumofsquares(x,y):
return square(x) + square(y)
!ls
%%timeit
sumofsquares(5, 7)
def square(x):
return x*x
def sumofsquares(x,y):
return square(x) + square(y)
%%timeit
sumofsquares(5, 7)
%%file cfib.pyx
from __future__ import print_function
def fib(n):
cdef int cur, prev
cur, prev = 1,1
while cur < n:
cur, prev = cur+prev, cur
print(cur, end=",")
%%file setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("cfib.pyx"))
!python setup.py build_ext --inplace
!ls
import cfib
cfib.fib(1000)
!rm cfib.pyx
cfib.fib(1000)
cfib.fib('5')
%%file simple.c
int add(int x, int y ){
return(x+y);
}
!gcc -c simple.c
!gcc -shared -o libsimple.so simple.o
!ls libsimple.so
import ctypes
import os
_file = "libsimple.so"
_path = os.path.join(os.getcwd(), _file)
_module = ctypes.cdll.LoadLibrary(_path)
add = _module.add
add.argtypes = [ctypes.c_int, ctypes.c_int]
add.restype = ctypes.c_int
add(5, 8)
from numba import jit
@jit
def add(x,y):
return x+y
@jit(nogil=True)
def saxpy(n):
s = 0
for i in range(n):
for j in range(n):
s += i*j*1.0
return s
def saxpy1(n):
s = 0
for i in range(n):
for j in range(n):
s += i*j*1.0
return s
%%timeit
saxpy1(1000)
%%timeit
saxpy(1000)
@jit(nopython=True)
def saxpy2(n):
s = 0
for i in range(n):
for j in range(n):
s += i*j*1.0
return s
@jit(nogil=True, parallel=True)
def twice():
return saxpy2(1000) + saxpy2(1000)
%%timeit
twice()