Skip to content

Instantly share code, notes, and snippets.

@honzajavorek
Last active December 16, 2015 13:29
Show Gist options
  • Save honzajavorek/5442491 to your computer and use it in GitHub Desktop.
Save honzajavorek/5442491 to your computer and use it in GitHub Desktop.
"Decorate to register"
###
### I want to collect some functions (or classes) for further use.
###
# Option 1: IMPLICIT (similar to CONVENTION OVER CONFIGURATION)
# Convention = all functions have the same prefix.
def compute_bullshit(...):
pass
def compute_butt(...):
pass
def compute_shiny_metal_ass(...):
pass
# Here we define a factory containing extremely unreadable,
# potentially dangerous (read as 'leading to mistakes'),
# and non-elegant magic to somehow figure out what to return.
def compute(name, *args, **kwargs):
fn = globals()['compute_' + name]
return fn(*args, **kwargs)
# Imagine at least 20 different 'whatifs', including:
# - What if the name is invalid and the function does not exist?
# - What if there occures a function prefixed 'compute_' which is
# for whatever reason not supposed to be called this way?
# - What if those functions are not in single module? more magic?
# - What if ...
# Option 2a: EXPLICIT (similar to CONFIGURATION OVER CONVENTION)
repository = {}
def compute_bullshit(...):
pass
def compute_butt(...):
pass
def compute_shiny_metal_ass(...):
pass
# This is brilliant! All explicit, clear, no magic, no mistakes...
# Wait... Is it brilliant? No. This is good for small cases, but later
# it is a lot of tedious work. Does not comply with DRY and laziness.
# No one wants to write this unless he/she is paid by hourly rate ;-)
repository['bullshit'] = compute_bullshit
repository['butt'] = compute_butt
repository['shiny_metal_ass'] = compute_shiny_metal_ass
def compute(name, *args, **kwargs):
fn = repository[name]
return fn(*args, **kwargs)
# Option 2b: EXPLICIT & DECLARATIVE
repository = {}
# decorator to explicitly register functions
def computation(name=None):
def wrapper(fn):
name = name or fn.__name__
repository[name] = fn
return fn
return wrapper
# All explicit, clear, no magic, no mistakes, DRY
# approach. See it in action:
@computation('bullshit') # results in registry['bullshit'] = fn
def compute_bullshit(...):
pass
@computation() # results in registry['compute_butt'] = fn
def compute_butt(...):
pass
@computation('shiny_ass') # results in registry['shiny_ass'] = fn
def compute_shiny_metal_ass(...):
pass
def compute(name, *args, **kwargs):
fn = repository[name]
return fn(*args, **kwargs)
# Note: This would be even better...
def compute(name, *args, **kwargs):
try:
fn = repository[name]
except KeyError:
raise ValueError('No such computation available: {0}'.format(name))
return fn(*args, **kwargs)
@paveldedik
Copy link

Thank you for this brilliant example ;) (now I see what you meant)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment