Advanced Python Training at Arcesium - Day 3

Sep 25-27, 2019 Vikrant Patil

These notes are available online at http://notes.pipal.in/2020/arcesium_advanced_feb/day3.html

© Pipal Academy LLP

Day 1 | Day 2 | Day 3

We will be using python 3.7 from anaconda for this training. You can download it from

https://www.anaconda.com/download/

OOPS

In [1]:
%%file bank0.py

balance = 0

def get_balance():
    return balance

def withdraw(amount):
    global balance
    balance -= amount
    
def deposit(amount):
    global balance
    balance += amount
Writing bank0.py
In [2]:
import bank0
In [3]:
bank0.get_balance()
Out[3]:
0
In [4]:
%%file bank1.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
Writing bank1.py
In [5]:
import bank1
In [6]:
a1 = bank1.make_account()
a2 = bank1.make_account()
In [7]:
bank1.deposit(a1, 10000)
In [8]:
bank1.withdraw(a1, 3000)
In [9]:
bank1.get_balance(a1)
Out[9]:
7000
In [10]:
class BankAccount:
    
    def __init__(self, balance):
        self.balance = balance
        
    def get_balance(self):
        return self.balance
    
    def withdraw(self, amount):
        self.balance -= amount
        
    def deposit(self, amount):
        self.balance += amount
In [11]:
b1 = BankAccount(10000)
In [12]:
b2 = BankAccount(0)
In [13]:
BankAccount
Out[13]:
__main__.BankAccount
In [14]:
b1
Out[14]:
<__main__.BankAccount at 0x7fe77788c278>
In [15]:
isinstance(b1, BankAccount)
Out[15]:
True

Class Vs Instance

In [16]:
class Point:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
In [17]:
p = Point(3, 5)
In [18]:
class Point2D:
    
    z = 0
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
In [19]:
p2 = Point2D(5, 6)
In [20]:
p2.x
Out[20]:
5
In [21]:
p2.y
Out[21]:
6
In [22]:
p2.z
Out[22]:
0
In [23]:
Point2D.x
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-23-e8084bdd8ecb> in <module>
----> 1 Point2D.x

AttributeError: type object 'Point2D' has no attribute 'x'
In [24]:
Point2D.z
Out[24]:
0
In [25]:
p21 = Point2D(2, 3)
In [26]:
p21.z
Out[26]:
0
In [27]:
Point2D.z = 100
In [28]:
p21.z
Out[28]:
100
In [29]:
p23 = Point2D(2,2)
In [30]:
p23.z
Out[30]:
100
In [32]:
p23.__dict__
Out[32]:
{'x': 2, 'y': 2}
In [33]:
p23.z = 20
In [34]:
Point2D.z
Out[34]:
100
In [35]:
p21.z
Out[35]:
100
In [36]:
p21.__dict__
Out[36]:
{'x': 2, 'y': 3}
In [37]:
p23.__dict__
Out[37]:
{'x': 2, 'y': 2, 'z': 20}
In [38]:
del p23.z
In [39]:
p23.z
Out[39]:
100
In [46]:
p23
Out[46]:
<__main__.Point2D at 0x7fe777850668>

Question

What is the dfference when I cann hello and bar methods on an instance?

In [40]:
class Foo:
    
    def hello():
        pass
    
    def bar(self):
        pass
In [41]:
f = Foo()
In [42]:
f.hello()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-42-0ad620007be2> in <module>
----> 1 f.hello()

TypeError: hello() takes 0 positional arguments but 1 was given
In [43]:
f.bar()
In [44]:
Foo.hello()
In [45]:
f
Out[45]:
<__main__.Foo at 0x7fe777898dd8>
In [47]:
Foo.hello
Out[47]:
<function __main__.Foo.hello()>
In [48]:
Foo.bar
Out[48]:
<function __main__.Foo.bar(self)>
In [49]:
f.hello
Out[49]:
<bound method Foo.hello of <__main__.Foo object at 0x7fe777898dd8>>
In [50]:
f.bar
Out[50]:
<bound method Foo.bar of <__main__.Foo object at 0x7fe777898dd8>>

Customising classes

In [52]:
a = [1,2]
a
Out[52]:
[1, 2]
In [53]:
class Point:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    
In [54]:
p = Point(1,2)
In [55]:
p
Out[55]:
<__main__.Point at 0x7fe77740a1d0>
In [56]:
class Point:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return "Point({},{})".format(self.x, self.y)
In [58]:
p = Point(2, 3)
In [59]:
p
Out[59]:
Point(2,3)
In [60]:
print(p)
Point(2,3)
In [61]:
class Point:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return "Point({},{})".format(self.x, self.y)
    
    def __str__(self):
        return "Point<{},{}>".format(self.x, self.y)
In [63]:
p = Point(1, 2)
In [64]:
p
Out[64]:
Point(1,2)
In [65]:
print(p)
Point<1,2>
In [66]:
len([1,2,3,4])
Out[66]:
4
In [67]:
len("2323  4232 432 4 salkdjsad  fsldkj")
Out[67]:
34
In [68]:
len({"a":1})
Out[68]:
1
In [69]:
len({1, 2, 3})
Out[69]:
3
In [70]:
len(p)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-70-3d9d6586c8d9> in <module>
----> 1 len(p)

TypeError: object of type 'Point' has no len()
In [71]:
class Vector:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return "Vector({},{})".format(self.x, self.y)
    
    def __str__(self):
        return "Vector<{},{}>".format(self.x, self.y)
    
    def __len__(self):
        return (self.x**2 + self.y**2)**0.5
In [72]:
v = Vector(1,1)
In [73]:
len(v)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-73-a878aa1e2fde> in <module>
----> 1 len(v)

TypeError: 'float' object cannot be interpreted as an integer
In [75]:
class Vector:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return "Vector({},{})".format(self.x, self.y)
    
    def __str__(self):
        return "Vector<{},{}>".format(self.x, self.y)
    
    def __len__(self):
        return int((self.x**2 + self.y**2)**0.5)
In [78]:
v = Vector(20,1)
In [79]:
len(v)
Out[79]:
20
In [80]:
class Pair:
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return "Pair({},{})".format(self.x, self.y)
    
    def __str__(self):
        return "Pair<{},{}>".format(self.x, self.y)
    
    def __len__(self):
        return 2
In [82]:
len(Foo())
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-82-955ff12672b5> in <module>
----> 1 len(Foo())

TypeError: object of type 'Foo' has no len()
In [83]:
dir(1)
Out[83]:
['__abs__',
 '__add__',
 '__and__',
 '__bool__',
 '__ceil__',
 '__class__',
 '__delattr__',
 '__dir__',
 '__divmod__',
 '__doc__',
 '__eq__',
 '__float__',
 '__floor__',
 '__floordiv__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getnewargs__',
 '__gt__',
 '__hash__',
 '__index__',
 '__init__',
 '__init_subclass__',
 '__int__',
 '__invert__',
 '__le__',
 '__lshift__',
 '__lt__',
 '__mod__',
 '__mul__',
 '__ne__',
 '__neg__',
 '__new__',
 '__or__',
 '__pos__',
 '__pow__',
 '__radd__',
 '__rand__',
 '__rdivmod__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rfloordiv__',
 '__rlshift__',
 '__rmod__',
 '__rmul__',
 '__ror__',
 '__round__',
 '__rpow__',
 '__rrshift__',
 '__rshift__',
 '__rsub__',
 '__rtruediv__',
 '__rxor__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__sub__',
 '__subclasshook__',
 '__truediv__',
 '__trunc__',
 '__xor__',
 'bit_length',
 'conjugate',
 'denominator',
 'from_bytes',
 'imag',
 'numerator',
 'real',
 'to_bytes']
In [85]:
x = 4545454
In [86]:
x.__add__(2)
Out[86]:
4545456

problem

  • + -> __add__(self, c)
  • - -> __sub__(self, c)
  • == -> __eq__(self, c)
  • [] -> __getitem__(self, name) and __setitem__(self, name, value)

Controlling attributes

In [87]:
class Sealed:
    
    def __setattr__(self, key, value):
        raise Exception("No way!")
In [88]:
s = Sealed()
In [89]:
s.x = 34
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-89-b6aab45d5993> in <module>
----> 1 s.x = 34

<ipython-input-87-f13a1fb6623c> in __setattr__(self, key, value)
      2 
      3     def __setattr__(self, key, value):
----> 4         raise Exception("No way!")

Exception: No way!
In [90]:
class UpperCase:
    
    def __getattr__(self, key):
        return key.upper()
In [91]:
u = UpperCase()
In [92]:
u.hello
Out[92]:
'HELLO'

problem

  • Write immutable Point class, once created can not be modified later.
In [93]:
class Point:
    
    def __init__(self, x, y):
        self.x = x
        self.x = y
        
    def __setattr__(self, key, value):
        raise Exception("Point is immutable class, can not modify it!")
In [94]:
class Foo:
    
    def __init__(self, x):
        self.x = x
In [96]:
f = Foo(3)
In [98]:
f.__dict__
Out[98]:
{'x': 3}
In [99]:
p = Point(4,5)
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-99-2aa77ddd0991> in <module>
----> 1 p = Point(4,5)

<ipython-input-93-773109dbceec> in __init__(self, x, y)
      2 
      3     def __init__(self, x, y):
----> 4         self.x = x
      5         self.x = y
      6 

<ipython-input-93-773109dbceec> in __setattr__(self, key, value)
      6 
      7     def __setattr__(self, key, value):
----> 8         raise Exception("Point is immutable class, can not modify it!")

Exception: Point is immutable class, can not modify it!
In [103]:
class Point:
    
    def __init__(self, x, y):
        self.__dict__['x'] = x
        self.__dict__['y'] = y
        
    def __setattr__(self, key, value):
        raise Exception("Point is immutable class, can not modify it!")
        
        
class Point:
    
    def __init__(self, x, y):
        super(Point, self).__setattr__("x", x)
        super(Point, self).__setattr__("y", y) 
        
    def __setattr__(self, key, value):
        raise Exception("Point is immutable class, can not modify it!")
        
        
In [105]:
p = Point(2, 3)
In [106]:
p.x = 34
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-106-0d9f79f7e8ae> in <module>
----> 1 p.x = 34

<ipython-input-103-9d42b750444c> in __setattr__(self, key, value)
     16 
     17     def __setattr__(self, key, value):
---> 18         raise Exception("Point is immutable class, can not modify it!")
     19 
     20 

Exception: Point is immutable class, can not modify it!
In [107]:
p.x
Out[107]:
2
In [207]:
p.__dict__['x'] = 10
In [108]:
class Foo:
    
    def __init__(self, x):
        self.x = x
        
    def doublex(self):
        self.x = 2*self.x
        
In [110]:
f = Foo(3)
In [111]:
Foo.doublex(f)
In [112]:
f.x
Out[112]:
6
In [113]:
Foo.doublex
Out[113]:
<function __main__.Foo.doublex(self)>
In [116]:
Foo.hello = lambda x: print("Hello ", x.x)
In [117]:
f.hello()
Hello  6
In [ ]:
Foo.hello()

multiple inheritnace

In [118]:
class A:
    pass

class B:
    pass

class C(A,B):
    pass
In [119]:
C.__mro__
Out[119]:
(__main__.C, __main__.A, __main__.B, object)

clasmethods and staticmethods

In [120]:
class Myint:
    
    def __init__(self, strnum):
        self.value = int(strnum)
        
    def parse(strnum):
        return int(strnum)
In [121]:
Myint.parse("100")
Out[121]:
100
In [122]:
int_ = Myint("23")
In [123]:
int_.parse("100")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-123-32ec462a59d2> in <module>
----> 1 int_.parse("100")

TypeError: parse() takes 1 positional argument but 2 were given
In [124]:
class Myint:
    
    def __init__(self, strnum):
        self.value = int(strnum)
    
    @staticmethod
    def parse(strnum):
        return int(strnum)
In [125]:
Myint.parse
Out[125]:
<function __main__.Myint.parse(strnum)>
In [128]:
a = Myint("34")
In [129]:
a.parse("100")
Out[129]:
100
In [130]:
import datetime
In [131]:
class MyDatetime(datetime.datetime):
    pass
In [132]:
datetime.datetime.now()
Out[132]:
datetime.datetime(2020, 2, 19, 13, 12, 27, 252642)
In [133]:
MyDatetime.now()
Out[133]:
MyDatetime(2020, 2, 19, 13, 12, 53, 101817)
In [134]:
class A:
    
    def instance():
        return A()
    
class B(A):
    pass
In [135]:
A.instance()
Out[135]:
<__main__.A at 0x7fe77789a7b8>
In [136]:
B.instance()
Out[136]:
<__main__.A at 0x7fe7778b4fd0>
In [137]:
class A:
    
    @classmethod
    def instance(cls):
        return cls()
    
class B(A):
    pass
In [140]:
A.instance()
Out[140]:
<__main__.A at 0x7fe777884470>
In [141]:
B.instance()
Out[141]:
<__main__.B at 0x7fe7778b43c8>
In [143]:
class C:
    
    def __init__(self, x):
        self.x = x
    
    @classmethod
    def instance(cls, value):
        return cls(value)
    
class D(C):
    pass
In [144]:
D.instance(5)
Out[144]:
<__main__.D at 0x7fe77787b0b8>

Metaclasses

In [146]:
type(1)
Out[146]:
int
In [147]:
type(A)
Out[147]:
type
In [148]:
type(Foo)
Out[148]:
type
In [149]:
type(MyDatetime)
Out[149]:
type
In [150]:
class Meta(type):
    pass
In [151]:
class SubMetaclass(Meta):
    pass
In [152]:
SubMetaclass()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-152-8e851ff096cb> in <module>
----> 1 SubMetaclass()

TypeError: type.__new__() takes exactly 3 arguments (0 given)
In [153]:
class SubMetaClass(metaclass=Meta):
    pass
In [154]:
SubMetaClass()
Out[154]:
<__main__.SubMetaClass at 0x7fe77768a8d0>
In [155]:
type(SubMetaClass)
Out[155]:
__main__.Meta
In [194]:
class Singleton(type):
    
    def __init__(self, *args, **kwargs):
        print(args)
        print(kwargs)
        self._instance = None
        
    def __call__(self, *args, **kwargs):
        print("__call__", self,args,kwargs)
        if self._instance:
            return self._instance
        else:
            self._instance = super().__call__(*args, **kwargs)
            return self._instance
In [195]:
        
class SingletonBase(metaclass=Singleton):
    pass
('SingletonBase', (), {'__module__': '__main__', '__qualname__': 'SingletonBase'})
{}
In [205]:
class X(SingletonBase):
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    pass
('X', (<class '__main__.SingletonBase'>,), {'__module__': '__main__', '__qualname__': 'X', '__init__': <function X.__init__ at 0x7fe77751a0d0>})
{}
In [200]:
x1 = X(2,3)
__call__ <class '__main__.X'> (2, 3) {}
In [203]:
del X
In [206]:
x2 = X()
__call__ <class '__main__.X'> () {}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-206-5266e7b45478> in <module>
----> 1 x2 = X()

<ipython-input-194-3441212e017b> in __call__(self, *args, **kwargs)
     11             return self._instance
     12         else:
---> 13             self._instance = super().__call__(*args, **kwargs)
     14             return self._instance

TypeError: __init__() missing 2 required positional arguments: 'x' and 'y'
In [193]:
x2
Out[193]:
<__main__.X at 0x7fe7777bf198>
In [163]:
 
Out[163]:
140632117959200
In [164]:
x1 is x2
Out[164]:
True
In [216]:
class Test:
    def __call__(self, *args, **kwargs):
        print(*args, **kwargs)
In [218]:
Test()(2323,2323)
2323 2323

Class decorators

In [222]:
def debug(func):
    prefix = "*"*10
    msg = prefix + func.__qualname__
    
    def wrapper(*args, **kwargs):
        print(msg)
        return func(*args, **kwargs)
    return wrapper
    

def debugmethod(cls):
    for name, val in vars(cls).items():
        if callable(val):
            setattr(cls, name, debug(val))
    return cls

@debugmethod
class Foo:
    
    x = "xyz"
    
    def method1(self):
        pass
    
    def method2(self):
        pass
    
    def method2(self):
        pass
        
In [223]:
f = Foo()
In [224]:
f.method1()
**********Foo.method1
In [233]:
def singlton(cls):
    instance = None
    
    def wrapper(*args, **kwargs):
        nonlocal instance
        if instance == None:
            instance = cls(*args, **kwargs)
        return instance
    
    return wrapper

@singlton
class A:
    pass

@singlton
class B:
    pass
In [234]:
a1 = A()
In [235]:
a2 = A()

Descpriptors

In [236]:
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 TypeError("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)
In [237]:
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)
In [238]:
p = Point(2, 3)
__setattr__ of Point
__set__ from Integer<0.name!s>
__setattr__ of Point
__set__ from Integer<0.name!s>
In [239]:
p.x
__get__ from  Integer<0.name!s>
Out[239]:
2
In [240]:
p.y
__get__ from  Integer<0.name!s>
Out[240]:
3
In [241]:
p.x = 10
__setattr__ of Point
__set__ from Integer<0.name!s>
In [242]:
del p.x 
__del__ from Integer<0.name!s>
In [247]:
class Person:
    
    def __init__(self, name):
        self.name = name
        
    @property
    def email(self):
        return "@".join([self.name,"arcesium.com"])
        
    @email.setter
    def email(self):
        raise Execption("You can't modify email!")
In [248]:
p = Person("Praveen")
In [249]:
p.email
Out[249]:
'Praveen@arcesium.com'
In [250]:
p.email()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-250-7f3a24e54db6> in <module>
----> 1 p.email()

TypeError: 'str' object is not callable
In [251]:
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)
In [257]:
class Person:
    
    def __init__(self, name):
        self.name = name
        
    @my_property
    def email(self):
        return "@".join([self.name, "gmail.com"])
In [258]:
p = Person("vikrant")
In [259]:
p.email
my_property.__get__
Out[259]:
'vikrant@gmail.com'

Context managers

In [260]:
with open("data.csv") as f:
    f.read()
In [263]:
import time
class Timer:
    
    def __init__(self):
        self._start = 0
        self._end = 0
        
    def start(self):
        self._start = time.time()
        
    def stop(self):
        self._end = time.time()
        
    def get_time_taken(self):
        return self._end - self._start
    
class ContextTimer(Timer):
    
    def reset(self):
        self._start = 0
        self._end = 0
        
    def __enter__(self):
        print("Begining with block")
        self.reset()
        self.start()
        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.get_time_taken())
In [265]:
with ContextTimer() as t:
    print("Inside with body!")
    for i in range(10000):
        for j in range(10000):
            s = i*j*1.0
    print("End of with body")
Begining with block
Inside with body!
End of with body
None None None
Time taken in with block:  11.490097761154175

Threading

In [266]:
import threading 
In [268]:
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("Task ..over")
Tick- 0
Tick-down- 9
Tick- 1
Tick-down- 8
Tick- 2
Tick-down- 7
Tick- 3
Tick-down- 6
Tick- 4
Tick-down- 5
Tick- 5
Tick-down- 4
Tick- 6
Tick-down- 3
Tick- 7
Tick-down- 2
Tick- 8
Tick-down- 1
Tick- 9
Tick-down- 0
Task ..over

communicating with thread

In [277]:
event = threading.Event()
In [278]:
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()
Tick- 0
Tick- 1
Tick- 2
Tick- 3
Tick- 4
Tick- 5
Tick- 6
In [279]:
event.set()
Tick- 7

sharing of data among thread

In [284]:
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)
In [285]:
data = [1,1,2,3,4]
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))
p.start()
c.start()
o.start()
time.sleep(3)
Produced... 0
Consumed ... 0
[1, 1, 2, 3, 4]
Produced... 1
Consumed ... 1
[1, 1, 2, 3, 4]
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
Produced... 0
[1, 1, 2, 3, 4, 0]
Consumed ... 0
Produced... 0
[1, 1, 2, 3, 4, 0]
Consumed ... 0
Produced... 0
[1, 1, 2, 3, 4, 0]
Consumed ... 0
Produced... 0
[1, 1, 2, 3, 4, 0]
Consumed ... 0
Produced... 0
[1, 1, 2, 3, 4, 0]
Consumed ... 0
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
Produced... 1
[1, 1, 2, 3, 4, 1]
Consumed ... 1
In [286]:
event.set()

threadpool/processpool

In [287]:
from multiprocessing.pool import ThreadPool
In [288]:
pool = ThreadPool(4)
In [290]:
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)
Begining with block
None None None
Time taken in with block:  85.40917158126831
Begining with block
None None None
Time taken in with block:  38.73597979545593
Begining with block
None None None
Time taken in with block:  23.030019521713257
Begining with block
None None None
Time taken in with block:  16.960930109024048
Begining with block
None None None
Time taken in with block:  24.618520975112915
Begining with block
None None None
Time taken in with block:  16.405393600463867
Begining with block
None None None
Time taken in with block:  15.920554637908936
Begining with block
None None None
Time taken in with block:  13.826315879821777

cputasks

In [293]:
class ContextTimer(Timer):
    
    def reset(self):
        self._start = 0
        self._end = 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.get_time_taken())
        
from multiprocessing.pool import Pool

def saxpy(n):
    s = 0
    for i in range(n):
        for j in range(n//10):
            s += j*i*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)
Time taken in with block:  7.856967926025391
Time taken in with block:  4.79718804359436
Time taken in with block:  3.265000343322754
Time taken in with block:  2.6620309352874756
Time taken in with block:  2.747628688812256
Time taken in with block:  2.8313417434692383
Time taken in with block:  3.0607378482818604
Time taken in with block:  3.3329548835754395

Pandas

In [294]:
import pandas as pd
In [295]:
area = pd.Series(["North", "East", "West", "South", "Central"])
In [296]:
area
Out[296]:
0      North
1       East
2       West
3      South
4    Central
dtype: object
In [297]:
sales = pd.Series([2,25,15,20,10], index=area)
In [298]:
sales
Out[298]:
North       2
East       25
West       15
South      20
Central    10
dtype: int64
In [299]:
sales['North']
Out[299]:
2
In [300]:
sales[0]
Out[300]:
2
In [301]:
area
Out[301]:
0      North
1       East
2       West
3      South
4    Central
dtype: object
In [302]:
area[0]
Out[302]:
'North'
In [303]:
area[4]
Out[303]:
'Central'
In [304]:
area[area=="Central"]
Out[304]:
4    Central
dtype: object
In [305]:
sales
Out[305]:
North       2
East       25
West       15
South      20
Central    10
dtype: int64
In [307]:
sales.reindex(index=sorted(area))
Out[307]:
Central    10
East       25
North       2
South      20
West       15
dtype: int64
In [308]:
sales
Out[308]:
North       2
East       25
West       15
South      20
Central    10
dtype: int64
In [309]:
reordred = sales.reindex(index=sorted(area))
In [310]:
reordred
Out[310]:
Central    10
East       25
North       2
South      20
West       15
dtype: int64
In [311]:
sales.mean()
Out[311]:
14.4
In [312]:
sales.std()
Out[312]:
8.905054744357274
In [313]:
sales[sales>10]
Out[313]:
East     25
West     15
South    20
dtype: int64

Dataframe

In [314]:
df = pd.DataFrame({"sales":[20,23,12,6,25],
                   "profit":[5,2,7,1,8]
                  }, index=["North", "East", "West", "South", "Central"]
                 )
In [315]:
df
Out[315]:
sales profit
North 20 5
East 23 2
West 12 7
South 6 1
Central 25 8
In [316]:
df['sales']
Out[316]:
North      20
East       23
West       12
South       6
Central    25
Name: sales, dtype: int64
In [317]:
df.sales
Out[317]:
North      20
East       23
West       12
South       6
Central    25
Name: sales, dtype: int64
In [318]:
df.head()
Out[318]:
sales profit
North 20 5
East 23 2
West 12 7
South 6 1
Central 25 8
In [320]:
weather = pd.read_csv("HYDERABAD-weather.csv")
In [321]:
weather.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 599 entries, 0 to 598
Data columns (total 7 columns):
Unnamed: 0    599 non-null int64
city          599 non-null object
month         599 non-null object
year          599 non-null int64
maxtemp       599 non-null float64
mintemp       599 non-null float64
rainfall      598 non-null float64
dtypes: float64(3), int64(2), object(2)
memory usage: 32.8+ KB
In [322]:
weather.isnull().sum()
Out[322]:
Unnamed: 0    0
city          0
month         0
year          0
maxtemp       0
mintemp       0
rainfall      1
dtype: int64
In [323]:
weather.head()
Out[323]:
Unnamed: 0 city month year maxtemp mintemp rainfall
0 0 HYDERABAD January 1951 29.0 14.8 0.0
1 1 HYDERABAD January 1952 29.1 13.6 0.0
2 2 HYDERABAD January 1953 28.6 14.6 3.5
3 3 HYDERABAD January 1954 28.2 13.9 0.0
4 4 HYDERABAD January 1955 28.0 14.7 0.0
In [324]:
weather.tail()
Out[324]:
Unnamed: 0 city month year maxtemp mintemp rainfall
594 594 HYDERABAD December 1996 28.3 14.9 0.0
595 595 HYDERABAD December 1997 28.7 19.2 40.6
596 596 HYDERABAD December 1998 28.7 12.8 0.0
597 597 HYDERABAD December 1999 29.0 14.2 0.0
598 598 HYDERABAD December 2000 29.6 13.3 1.0
In [325]:
df
Out[325]:
sales profit
North 20 5
East 23 2
West 12 7
South 6 1
Central 25 8
In [326]:
df.loc['East']
Out[326]:
sales     23
profit     2
Name: East, dtype: int64
In [328]:
df['sales']
Out[328]:
North      20
East       23
West       12
South       6
Central    25
Name: sales, dtype: int64
In [329]:
df.loc['East']['profit']
Out[329]:
2
In [330]:
df.iloc[3]
Out[330]:
sales     6
profit    1
Name: South, dtype: int64
In [331]:
weather.groupby("month").mean()
Out[331]:
Unnamed: 0 year maxtemp mintemp rainfall
month
April 174.0 1975.77551 37.863265 24.273469 20.234694
August 373.5 1975.50000 29.786000 22.086000 178.690000
December 573.5 1975.50000 28.004000 14.526000 5.912000
February 74.5 1975.50000 31.932000 17.556000 7.940000
January 24.5 1975.50000 28.760000 15.214000 13.178000
July 323.5 1975.50000 30.754000 22.560000 169.860000
June 273.5 1975.50000 34.528000 23.976000 103.754000
March 124.5 1975.50000 35.444000 20.798000 15.264000
May 223.5 1975.50000 38.996000 26.160000 35.714000
November 523.5 1975.50000 29.016000 16.862000 22.420408
October 473.5 1975.50000 30.582000 20.306000 97.158000
September 423.5 1975.50000 30.452000 21.962000 158.292000
In [335]:
(weather.groupby("month")
        .mean()
        .plot
        .line(y=["maxtemp"]))
Out[335]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fe64bb68400>
In [334]:
%matplotlib inline
In [336]:
(weather.groupby("month")
        .mean()
        .plot
        .line(y=["maxtemp","mintemp","rainfall"]))
Out[336]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fe64badc748>
In [337]:
(weather.groupby("month")
        .mean()
        .plot
        .bar(y=["maxtemp","mintemp","rainfall"]))
Out[337]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fe64bbafbe0>
In [338]:
pd.read_sql_table?
In [339]:
help(pd.read_sql)
Help on function read_sql in module pandas.io.sql:

read_sql(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, columns=None, chunksize=None)
    Read SQL query or database table into a DataFrame.
    
    This function is a convenience wrapper around ``read_sql_table`` and
    ``read_sql_query`` (for backward compatibility). It will delegate
    to the specific function depending on the provided input. A SQL query
    will be routed to ``read_sql_query``, while a database table name will
    be routed to ``read_sql_table``. Note that the delegated function might
    have more specific notes about their functionality not listed here.
    
    Parameters
    ----------
    sql : string or SQLAlchemy Selectable (select or text object)
        SQL query to be executed or a table name.
    con : SQLAlchemy connectable (engine/connection) or database string URI
        or DBAPI2 connection (fallback mode)
    
        Using SQLAlchemy makes it possible to use any DB supported by that
        library. If a DBAPI2 object, only sqlite3 is supported.
    index_col : string or list of strings, optional, default: None
        Column(s) to set as index(MultiIndex).
    coerce_float : boolean, default True
        Attempts to convert values of non-string, non-numeric objects (like
        decimal.Decimal) to floating point, useful for SQL result sets.
    params : list, tuple or dict, optional, default: None
        List of parameters to pass to execute method.  The syntax used
        to pass parameters is database driver dependent. Check your
        database driver documentation for which of the five syntax styles,
        described in PEP 249's paramstyle, is supported.
        Eg. for psycopg2, uses %(name)s so use params={'name' : 'value'}
    parse_dates : list or dict, default: None
        - List of column names to parse as dates.
        - Dict of ``{column_name: format string}`` where format string is
          strftime compatible in case of parsing string times, or is one of
          (D, s, ns, ms, us) in case of parsing integer timestamps.
        - Dict of ``{column_name: arg dict}``, where the arg dict corresponds
          to the keyword arguments of :func:`pandas.to_datetime`
          Especially useful with databases without native Datetime support,
          such as SQLite.
    columns : list, default: None
        List of column names to select from SQL table (only used when reading
        a table).
    chunksize : int, default None
        If specified, return an iterator where `chunksize` is the
        number of rows to include in each chunk.
    
    Returns
    -------
    DataFrame
    
    See Also
    --------
    read_sql_table : Read SQL database table into a DataFrame.
    read_sql_query : Read SQL query into a DataFrame.

In [340]:
groupbymonth = weather.groupby("month").max()
In [341]:
groupbymonth
Out[341]:
Unnamed: 0 city year maxtemp mintemp rainfall
month
April 198 HYDERABAD 2000 39.9 26.5 70.3
August 398 HYDERABAD 2000 32.2 23.2 469.0
December 598 HYDERABAD 2000 29.8 19.2 94.5
February 99 HYDERABAD 2000 33.6 20.1 80.7
January 49 HYDERABAD 2000 30.6 17.9 400.0
July 348 HYDERABAD 2000 32.8 23.6 422.1
June 298 HYDERABAD 2000 37.6 25.8 215.7
March 149 HYDERABAD 2000 37.5 22.7 100.0
May 248 HYDERABAD 2000 41.4 28.3 178.8
November 548 HYDERABAD 2000 31.2 20.6 238.7
October 498 HYDERABAD 2000 33.4 21.6 324.5
September 448 HYDERABAD 2000 32.9 23.3 483.9
In [342]:
groupbymonth.describe()
Out[342]:
Unnamed: 0 year maxtemp mintemp rainfall
count 12.000000 12.0 12.000000 12.000000 12.000000
mean 323.250000 2000.0 34.408333 22.733333 256.516667
std 179.937426 0.0 3.768641 3.082010 157.779396
min 49.000000 2000.0 29.800000 17.900000 70.300000
25% 185.750000 2000.0 31.950000 20.475000 98.625000
50% 323.000000 2000.0 33.150000 22.950000 227.200000
75% 460.500000 2000.0 37.525000 24.150000 405.525000
max 598.000000 2000.0 41.400000 28.300000 483.900000

cython

In [343]:
%load_ext Cython
In [344]:
%%cython --annotate

def square(x):
    return x*x

def sumofsquares(x,y):
    return square(x) + square(y)
Out[344]:
Cython: _cython_magic_cbd2f9420c77f89c385ed6b164e06e13.pyx

Generated by Cython 0.29.12

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

 1: 
+2: def square(x):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_1square(PyObject *__pyx_self, PyObject *__pyx_v_x); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_1square = {"square", (PyCFunction)__pyx_pw_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_1square, METH_O, 0};
static PyObject *__pyx_pw_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_1square(PyObject *__pyx_self, PyObject *__pyx_v_x) {
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("square (wrapper)", 0);
  __pyx_r = __pyx_pf_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_square(__pyx_self, ((PyObject *)__pyx_v_x));

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_square(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_x) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("square", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("_cython_magic_cbd2f9420c77f89c385ed6b164e06e13.square", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple_ = PyTuple_Pack(1, __pyx_n_s_x); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple_);
  __Pyx_GIVEREF(__pyx_tuple_);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_1square, NULL, __pyx_n_s_cython_magic_cbd2f9420c77f89c38); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_square, __pyx_t_1) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(1, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_vikrant_cache_ipython_cyth, __pyx_n_s_square, 2, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) __PYX_ERR(0, 2, __pyx_L1_error)
+3:     return x*x
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = PyNumber_Multiply(__pyx_v_x, __pyx_v_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 3, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;
 4: 
+5: def sumofsquares(x,y):
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_3sumofsquares(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_3sumofsquares = {"sumofsquares", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_3sumofsquares, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_3sumofsquares(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_x = 0;
  PyObject *__pyx_v_y = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("sumofsquares (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_y,0};
    PyObject* values[2] = {0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_x)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_y)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("sumofsquares", 1, 2, 2, 1); __PYX_ERR(0, 5, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "sumofsquares") < 0)) __PYX_ERR(0, 5, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
    }
    __pyx_v_x = values[0];
    __pyx_v_y = values[1];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("sumofsquares", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 5, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_cbd2f9420c77f89c385ed6b164e06e13.sumofsquares", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_2sumofsquares(__pyx_self, __pyx_v_x, __pyx_v_y);

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_2sumofsquares(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("sumofsquares", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_AddTraceback("_cython_magic_cbd2f9420c77f89c385ed6b164e06e13.sumofsquares", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__3 = PyTuple_Pack(2, __pyx_n_s_x, __pyx_n_s_y); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__3);
  __Pyx_GIVEREF(__pyx_tuple__3);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_cbd2f9420c77f89c385ed6b164e06e13_3sumofsquares, NULL, __pyx_n_s_cython_magic_cbd2f9420c77f89c38); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_sumofsquares, __pyx_t_1) < 0) __PYX_ERR(0, 5, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+6:     return square(x) + square(y)
  __Pyx_XDECREF(__pyx_r);
  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_square); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 6, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_3 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
    __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
    if (likely(__pyx_t_3)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
      __Pyx_INCREF(__pyx_t_3);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_2, function);
    }
  }
  __pyx_t_1 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_2, __pyx_t_3, __pyx_v_x) : __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_x);
  __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
  if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 6, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_square); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 6, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_4 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  __pyx_t_2 = (__pyx_t_4) ? __Pyx_PyObject_Call2Args(__pyx_t_3, __pyx_t_4, __pyx_v_y) : __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_v_y);
  __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
  if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 6, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = PyNumber_Add(__pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 6, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_r = __pyx_t_3;
  __pyx_t_3 = 0;
  goto __pyx_L0;
In [345]:
%%timeit
sumofsquares(7, 10)
95.7 ns ± 0.202 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [346]:
def square(x):
    return x*x

def sumofsquares(x,y):
    return square(x) + square(y)
In [347]:
%%timeit
sumofsquares(7,10)
203 ns ± 4.44 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [351]:
%%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=",")
    
    
Overwriting cfib.pyx
In [352]:
%%file setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("cfib.pyx"))
Overwriting setup.py
In [353]:
!python setup.py build_ext --inplace
Compiling cfib.pyx because it changed.
[1/1] Cythonizing cfib.pyx
/home/vikrant/anaconda3/lib/python3.7/site-packages/Cython/Compiler/Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: /home/vikrant/trainings/2020/arcesium_advanced_feb/cfib.pyx
  tree = Parsing.p_module(s, pxd, full_module_name)
running build_ext
building 'cfib' extension
creating build
creating build/temp.linux-x86_64-3.7
gcc -pthread -B /home/vikrant/anaconda3/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/vikrant/anaconda3/include/python3.7m -c cfib.c -o build/temp.linux-x86_64-3.7/cfib.o
gcc -pthread -shared -B /home/vikrant/anaconda3/compiler_compat -L/home/vikrant/anaconda3/lib -Wl,-rpath=/home/vikrant/anaconda3/lib -Wl,--no-as-needed -Wl,--sysroot=/ build/temp.linux-x86_64-3.7/cfib.o -o /home/vikrant/trainings/2020/arcesium_advanced_feb/cfib.cpython-37m-x86_64-linux-gnu.so
In [354]:
!ls
Advanced_Python_Pre_Assessment.csv    day1.ipynb	     memoize.py
bank0.py			      day2.html		     numeric.csv
bank1.py			      day2.ipynb	     pandp.txt
build				      day3.html		     push
cfib.c				      day3.ipynb	     __pycache__
cfib.cpython-37m-x86_64-linux-gnu.so  fib1.py		     sales.txt
cfib.pyx			      fib.py		     setup.py
data.csv			      HYDERABAD-weather.csv  trace.py
data.db				      looping.py
day1.html			      Makefile
In [355]:
import cfib
In [357]:
cfib.fib(1000)
2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,

cextensions

In [358]:
%%file simple.c

int add(int x, int y){
    return(x+y);
}
Writing simple.c
In [359]:
!gcc -c simple.c
In [360]:
!gcc -shared -o libsimple.so simple.o
In [361]:
!ls
Advanced_Python_Pre_Assessment.csv    day2.html		     numeric.csv
bank0.py			      day2.ipynb	     pandp.txt
bank1.py			      day3.html		     push
build				      day3.ipynb	     __pycache__
cfib.c				      fib1.py		     sales.txt
cfib.cpython-37m-x86_64-linux-gnu.so  fib.py		     setup.py
cfib.pyx			      HYDERABAD-weather.csv  simple.c
data.csv			      libsimple.so	     simple.o
data.db				      looping.py	     trace.py
day1.html			      Makefile
day1.ipynb			      memoize.py
In [362]:
import ctypes
In [363]:
import os
In [364]:
_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(8,10)
Out[364]:
18

numba

In [365]:
from numba import jit

@jit
def add(x, y):
    return x+y
In [372]:
@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
In [375]:
def saxpy_(n):
    s = 0
    for i in range(n):
        for j in range(n):
            s += i*j*1.0
    return s
In [377]:
%%timeit
saxpy_(1000)
79.3 ms ± 978 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [378]:
%%timeit
saxpy(1000)
1.18 ms ± 4.83 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

References

In [ ]: