In [ ]:
class count_calls:
def __init__(self, f):
self.count = 0
self.f = f
def __call__(self, *args, **kwargs):
self.count += 1
print('Count nb {} to {}'.format(self.count, self.f))
return self.f(*args, **kwargs)
# Equivalent to:
# add_up = count_calls(add_up)
@count_calls
def add_up(x, y, *, a, b):
return x + y + a + b
print(add_up(1, 2, a = 2, b = 3))
print(add_up(4, 5, a = 6, b = 7))
print(add_up(8, 9, a = 10, b = 11))
In [ ]:
def count_calls(f):
count = 0
def wrap(*args, **kwargs):
nonlocal count
count += 1
print('Count nb {} to {}'.format(count, f))
return f(*args, **kwargs)
return wrap
# Equivalent to:
# add_up = count_calls(add_up)
@count_calls
def add_up(x, y, *, a, b):
return x + y + a + b
print(add_up(1, 2, a = 2, b = 3))
print(add_up(4, 5, a = 6, b = 7))
print(add_up(8, 9, a = 10, b = 11))
In [ ]:
def count_calls_starting_from(start = 0):
def count_calls(f):
count = start
def wrap(*args, **kwargs):
nonlocal count
count += 1
print('Count nb {} to {}'.format(count, f))
return f(*args, **kwargs)
return wrap
return count_calls
# Equivalent to:
# add_up = count_calls_starting_from(1)(add_up)
@count_calls_starting_from(1)
def add_up(x, y, *, a, b):
return x + y + a + b
print(add_up(1, 2, a = 2, b = 3))
print(add_up(4, 5, a = 6, b = 7))
print(add_up(8, 9, a = 10, b = 11))
In [ ]:
def count_calls(cls):
def wrap(datum):
wrap.count += 1
print('Count nb {} to {}'.format(wrap.count, cls))
return cls(datum)
wrap.count = 0
return wrap
# Equivalent to:
# C = count_calls(C)
@count_calls
class C:
def __init__(self, datum):
self.datum = datum
I1, I2, I3 = C(11), C(12), C(13)
print(I1.datum, I2.datum, I3.datum)
In [ ]:
class C:
count_1 = 0
count_2 = 0
def __init__(self):
C.count_1 += 1
C.count_2 += 1
def display_count_1(mark):
print('count_1' + mark, C.count_1)
# Equivalent to:
# display_count_2 = staticmethod(display_count_2)
@staticmethod
def display_count_2(mark):
print('count_2' + mark, C.count_2)
I1, I2, I3 = C(), C(), C()
C.display_count_1(':')
C.display_count_2('...')
I2.display_count_2(' ')
In [ ]:
class C:
count = 0
def __init__(self):
C.count += 1
# Equivalent to:
# display_count = classmethod(display_count)
@classmethod
def display_count(cls, mark):
print('count for {}'.format(cls.__name__) + mark, C.count)
I1, I2, I3 = C(), C(), C()
C.display_count('...')
I2.display_count(':')
A descriptor is any class with at least one of the three methods:
It is called:
In [ ]:
class D:
def __init__(self):
self.datum = 'Descriptor datum'
def __get__(self, instance, owner):
print(self.datum)
print(owner._datum)
return instance._datum
def __set__(self, instance, value):
self.datum = 'New descriptor datum'
instance._datum = value
def __delete__(self, instance):
print('Deleting instance datum')
del instance._datum
class C:
_datum = 'Owner datum'
def __init__(self):
self._datum = 'Instance datum'
datum = D()
I = C()
print(I.datum)
print()
I.datum = 'New instance value'
print(I.datum)
print()
del I.datum
print()
I = C()
print(I.datum)
In [ ]:
class DataDescriptor:
def __get__(self, instance, owner):
return 'X1'
def __set__(self, instance, owner):
pass
class NonDataDescriptor:
def __get__(self, instance, owner):
return 'X3'
class C:
x1 = DataDescriptor()
x3 = NonDataDescriptor()
def __init__(self):
self.x1 = 'x1'
self.x2 = 'x2'
I = C()
print(I.x1, I.x2, I.x3)
I.x3 = 'x3'
print(I.x3)
In [ ]:
class C:
def __init__(self, datum):
self._datum = datum
# Equivalent to:
# datum = property(fget = datum, fset = None, fdel = None, doc = None)
# Using that form would set C.datum.__doc__ to the value of doc;
# with the decorator, that value is instead 'For illustration purposes'.
@property
def datum(self):
'For illustration purposes'
print('You asked for the value of datum')
return self._datum
# C.datum is now a descriptor, with in particular
# - the built-in methods getter, setter and deleter;
# - the functions fget, fset, fdel;
# - the method-wrappers __get__, __set__, __delete__.
# C.datum.__get__ is a method wrapper of C.datum.fget (the function above).
# Equivalent to:
# datum = datum.setter(datum)
# Returns a copy of datum with C.datum.fset assigned the function below.
# C.datum.__set__ is a method wrapper of C.datum.fset.
@datum.setter
def datum(self, value):
print('You want to modify the value of datum')
self._datum = value
# Equivalent to:
# datum = datum.deleter(datum)
# Returns a copy of datum with C.datum.fdel assigned the function below.
# C.datum.__delete__ is a method wrapper of C.datum.fdel.
@datum.deleter
def datum(self):
print('You have decided to delete datum')
del self._datum
I = C(3)
print(I.datum)
print()
I.datum = 4
print()
print(I.datum)
print()
del I.datum