class A(object):
    def __init__(self, **kwargs):
        print('A.__init__ with {}'.format(kwargs))
        super(A, self).__init__()
class B(A):
    def __init__(self, **kwargs):
        print('B.__init__ with {}'.format(kwargs))
        super(B, self).__init__(**kwargs)
class C(A):
    def __init__(self, **kwargs):
        print('C.__init__ with {}'.format(kwargs))
        super(C, self).__init__(**kwargs)
class D(B, C):
    def __init__(self):
        print('D.__init__')
        super(D, self).__init__(a=1, b=2, x=3)

print(D.mro())
D()

class A(object):
    def __init__(self, a):
        self.a = a

class B(A):
    def __init__(self, b, **kw):
        self.b = b
        super(B, self).__init__(**kw)

class C(A):
    def __init__(self, c, **kw):
        self.c = c
        super(C, self).__init__(**kw)

class D(B, C):
    def __init__(self, a, b, c):
        super(D, self).__init__(a=a, b=b, c=c)


obj = D(1,2,3)

obj.a, obj.b, obj.c

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second before super"
        super(Second, self).__init__()
        print "second after super"

class Third(First):
    def __init__(self):
        print "third before super"
        super(Third, self).__init__()
        print "third after super"

class Fourth(Second, Third):
    def __init__(self):
        print "fourth before super"
        super(Fourth, self).__init__()
        print "that's it"

Fourth()

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second before super"
        super(Second, self).__init__(a=2)
        print "second after super"

class Third(First):
    def __init__(self, a):
        print "third before super"
        super(Third, self).__init__()
        print "third after super"

class Fourth(Second, Third):
    def __init__(self):
        print "fourth before super"
        super(Fourth, self).__init__()
        print "that's it"

Fourth()

Second()

"""
Explanation: <img src='http://pycircle.org/static/pycircle_big.png' style="margin-left:auto; margin-right:auto; height:70%; width:70%">
super
End of explanation
"""


class A():
    def suma(self, a, b):
        return a + b
    
class AzMnozeniem(A):
    def mnozenie(self, a, b):
        return a * b

k = AzMnozeniem()

k.mnozenie(3, 4)

k.suma(3, 4)

"""
Explanation: Metody wirtualne?
End of explanation
"""


class A(object):
    def __init__(self, a):
        self.a = a
    
    def __add__(self, other):
        self.a += other.a
        return self

(A(4) + A(5)).a

"""
Explanation: Przeciążanie operatorów
End of explanation
"""


import abc

class Person():
    __metaclass__ = abc.ABCMeta

    def __init__(self, name):
        self.name = name

    @abc.abstractmethod
    def say_hello(self):
        pass

class Programmer(Person):
    def __init__(self, name, language):
        Person.__init__(self, name)
        self.language = language

    def say_hello(self):
        print('Hello! I\'m %s and I write in %s.' % (self.name, self.language))

p = Person(name="Duck")
p

p = Programmer(name="Duck", language="Duck++")
p

p.say_hello()

"""
Explanation: object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
object.__add__(self, other)
object.__sub__(self, other)
object.__mul__(self, other)
object.__floordiv__(self, other)
object.__mod__(self, other)
object.__divmod__(self, other)
object.__pow__(self, other[, modulo])
object.__lshift__(self, other)
object.__rshift__(self, other)
object.__and__(self, other)
object.__xor__(self, other)
object.__or__(self, other)
Klasy abstrakcyjne
End of explanation
"""


class A(object):
    b = "0.001"
    def __init__(self, a):
        self.a = a

A.b

A.a

A(234).a

"""
Explanation: Atrybuty
End of explanation
"""


class A():
    j = 0
    for i in range(10):
        j += i

A.j

"""
Explanation: Ciekawostki
End of explanation
"""


import math
import random
class Pole(object):
    def __init__(self, r=2.):
        self.r = r
    def oblicz(self):
        return math.pi * (self.r**2)

n = 1000
def get_mean_cls(n=n):
    return sum([Pole(random.random()).oblicz() for i in range(n)])/float(n)
def get_mean(n=n):
    return sum([math.pi * (random.random()**2) for r in range(n)])/float(n)

%timeit get_mean_cls()

%timeit get_mean()

"""
Explanation: Prędkość
End of explanation
"""


class Kaczka(object):
    def __init__(self, dl_skrzydla):
        self.dl_skrzydla = dl_skrzydla
    
    def plyn(self):
        print "Chlup chlup"

k = Kaczka(124)
k.plyn()
k.dl_skrzydla

class Kaczuszka(Kaczka):
    def __init__(self, dl_skrzydla):
        self._dl_skrzydla = dl_skrzydla
    
    @property
    def dl_skrzydla(self):
        return self._dl_skrzydla / 2.
    
    @dl_skrzydla.setter
    def dl_skrzydla(self, value):
        self._dl_skrzydla = value

k = Kaczuszka(124)
k.plyn()
k.dl_skrzydla

k.dl_skrzydla = 100
k.dl_skrzydla

k.dl_skrzydla += 50

k.dl_skrzydla

"""
Explanation: Property
End of explanation
"""


