import torch import matplotlib.pyplot as plt import random import ipywidgets as widgets def f(o): print('hi') w = widgets.Button(description='Click me') w 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): _inner = lambda epoch: print(f"{exclamation}! We've finished epoch {epoch}!") return _inner slow_calculation(make_show_progress("Nice!")) def make_show_progress(exclamation): # Leading "_" is generally understood to be "private" def _inner(epoch): print(f"{exclamation}! We've finished epoch {epoch}!") return _inner slow_calculation(make_show_progress("Nice!")) f2 = make_show_progress("Terrific") slow_calculation(f2) slow_calculation(make_show_progress("Amazing")) 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(*args, **kwargs): print(f"args: {args}; kwargs: {kwargs}") f(3, 'a', thing1="hello") 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 __init__(self): pass 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' 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.foo