import torch import matplotlib.pyplot as plt import random import ipywidgets as widgets w = widgets.Button(description='Click me') w def f(o): print('hi') w.on_click(f) from time import sleep def slow_calculation(): res = 0 for i in range(5): res += i*i sleep(1) return res slow_calculation() def slow_calculation(cb=None): res = 0 for i in range(5): res += i*i sleep(1) if cb: cb(i) return res def show_progress(epoch): print(f"Awesome! We've finished epoch {epoch}!") slow_calculation(show_progress) slow_calculation(lambda o: print(f"Awesome! We've finished epoch {o}!")) def show_progress(exclamation, epoch): print(f"{exclamation}! We've finished epoch {epoch}!") slow_calculation(lambda o: show_progress("OK I guess", o)) def make_show_progress(exclamation): def _inner(epoch): print(f"{exclamation}! We've finished epoch {epoch}!") return _inner slow_calculation(make_show_progress("Nice!")) from functools import partial slow_calculation(partial(show_progress, "OK I guess")) f2 = partial(show_progress, "OK I guess") class ProgressShowingCallback(): def __init__(self, exclamation="Awesome"): self.exclamation = exclamation def __call__(self, epoch): print(f"{self.exclamation}! We've finished epoch {epoch}!") cb = ProgressShowingCallback("Just super") slow_calculation(cb) def f(*a, **b): print(f"args: {a}; kwargs: {b}") f(3, 'a', thing1="hello") def g(a,b,c=0): print(a,b,c) args = [1,2] kwargs = {'c':3} g(*args, **kwargs) def slow_calculation(cb=None): res = 0 for i in range(5): if cb: cb.before_calc(i) res += i*i sleep(1) if cb: cb.after_calc(i, val=res) return res class PrintStepCallback(): def before_calc(self, *args, **kwargs): print(f"About to start") def after_calc (self, *args, **kwargs): print(f"Done step") slow_calculation(PrintStepCallback()) class PrintStatusCallback(): def __init__(self): pass def before_calc(self, epoch, **kwargs): print(f"About to start: {epoch}") def after_calc (self, epoch, val, **kwargs): print(f"After {epoch}: {val}") slow_calculation(PrintStatusCallback()) def slow_calculation(cb=None): res = 0 for i in range(5): if cb and hasattr(cb,'before_calc'): cb.before_calc(i) res += i*i sleep(1) if cb and hasattr(cb,'after_calc'): if cb.after_calc(i, res): print("stopping early") break return res class PrintAfterCallback(): def after_calc (self, epoch, val): print(f"After {epoch}: {val}") if val>10: return True slow_calculation(PrintAfterCallback()) class SlowCalculator(): def __init__(self, cb=None): self.cb,self.res = cb,0 def callback(self, cb_name, *args): if not self.cb: return cb = getattr(self.cb,cb_name, None) if cb: return cb(self, *args) def calc(self): for i in range(5): self.callback('before_calc', i) self.res += i*i sleep(1) if self.callback('after_calc', i): print("stopping early") break class ModifyingCallback(): def after_calc (self, calc, epoch): print(f"After {epoch}: {calc.res}") if calc.res>10: return True if calc.res<3: calc.res = calc.res*2 calculator = SlowCalculator(ModifyingCallback()) calculator.calc() calculator.res class SloppyAdder(): def __init__(self,o): self.o=o def __add__(self,b): return SloppyAdder(self.o + b.o + 0.01) def __repr__(self): return str(self.o) a = SloppyAdder(1) b = SloppyAdder(2) a+b class A: a,b=1,2 a = A() a.b getattr(a, 'b') getattr(a, 'b' if random.random()>0.5 else 'a') class B: a,b=1,2 def __getattr__(self, k): if k[0]=='_': raise AttributeError(k) return f'Hello from {k}' b = B() b.a b.foo