Skip to content

Instantly share code, notes, and snippets.

@not-much-io
Created February 19, 2016 11:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save not-much-io/dc2b098528770658c667 to your computer and use it in GitHub Desktop.
Save not-much-io/dc2b098528770658c667 to your computer and use it in GitHub Desktop.
from inspect import signature
from uuid import uuid1
# Just a proof of concept implementation of destructuring in python
def destructurable_params(fn, args):
"""Return a list of dicts that contain destructuring expressions and the parameters values.
Parameters with no valid destructuring syntax will be ignored.
:param fn: Function of interest
:param args: argument tuple of the function
:return: a list of destructuring expressions and variable values
"""
params = signature(fn).parameters
to_destructure = []
for i, param in enumerate(params):
param = params[param]
value = args[i]
annotation_type = type(param.annotation) # Will be Parameter.Empty if not present
valid_expr = annotation_type == tuple or annotation_type == dict # any tuple or dict is valid
val_is_dict = type(value) == dict
if valid_expr and val_is_dict:
to_destructure.append({"destructuring_expression": param.annotation,
"variable_value": value})
return to_destructure
def tuple_destruct(expr, target_dict, fn, args):
"""Destructuring of a dict using a tuple.
d = {"a": 2}
d: ("a") => get "a" from d and assign to variable named a
Note:
Will use globals to make variables available in function scope
Will restore any other variables with the same name after fn has been run
:param expr: Destructuring expression (tuple)
:param target_dict: Dictionary to be destructuring
:param fn: Function that is wrapped (this function is called from a decorator)
:param args: Argument tuple of fn
:return: The result of running fn with the destructuring logic run
"""
old_vals = []
uuid = uuid1()
for key in expr:
try:
old_vals.append(globals()[key])
except KeyError:
old_vals.append(uuid)
globals()[key] = target_dict[key] # Maybe needs deep copy?
res = fn(*args)
for i, key in enumerate(expr):
old_val = old_vals[i]
if old_val == uuid:
globals()[key] = old_val
else:
del globals()[key]
return res
def dict_destructure(expr, target_dict, fn, args):
"""Destructuring of a dict using another dict.
d = {"a": 2}
d: {"var1": "a"} => get "a" from d and assign to variable named var1
Note:
Will use globals to make variables available in function scope
Will restore any other variables with the same name after fn has been run
:param expr: Destructuring expression (dict)
:param target_dict: Dictionary to be destructuring
:param fn: Function that is wrapped (this function is called from a decorator)
:param args: Argument tuple of fn
:return: The result of running fn with the destructuring logic run
"""
old_vals = {}
uuid = uuid1()
for var_name, key in expr.items():
try:
old_vals[var_name] = globals()[var_name]
except KeyError:
old_vals[var_name] = uuid
globals()[var_name] = target_dict[key] # Maybe needs deep copy?
res = fn(*args)
for var_name, key in expr.items():
old_val = old_vals[var_name]
if old_val == uuid:
globals()[key] = old_val
else:
del globals()[key]
return res
def destructure(fn):
def wrapper(*args, **kwargs):
params_to_destructure = destructurable_params(fn, args)
for param in params_to_destructure:
destruct_expression = param["destructuring_expression"]
target_dict = param["variable_value"]
if type(destruct_expression) == tuple:
return tuple_destruct(destruct_expression, target_dict, fn, args)
if type(destruct_expression) == dict:
return dict_destructure(destruct_expression, target_dict, fn, args)
return wrapper
# Destructuring with tuples is a quick hand for
# 1) Getting out elements form a dict
# 2) Putting them in variables with the same name as the key
def sum_key1_and_key2_regular(d):
key1 = d['key1']
key2 = d['key2']
return key1 + key2
# vs.
@destructure
def sum_key1_and_key2(d: ('key1', 'key2')):
return key1 + key2
# or
def to_full_name_regular(name_dict):
title = name_dict["title"]
first_name = name_dict["first_name"]
last_name = name_dict["last_name"]
return title + first_name + last_name
# vs.
@destructure
def to_full_name(name_dict: ("title",
"first_name",
"last_name")):
return title + first_name + last_name
# No imposed limitations on other parameters, work just as before.
@destructure
def greet(greeting, name_dict: ("title", "first_name", "last_name")):
return greeting + title + first_name + last_name
# Destructuring with dictionaries is a quick hand to:
# 1) Get out elements from a dictionary
# 2) Put the value in a variable with the designated name
@destructure
def quadratic_equation(q_eq_data: {"a": "quadratic coefficient",
"b": "linear coefficient",
"x": "potential solution",
"c": "constant"}):
"""ax^2 + bx + c"""
assert a != 0
return a * pow(x, 2) + b * x + c
if __name__ == "__main__":
data = {"key1": 2,
"key2": 1}
print(
sum_key1_and_key2(data)
)
name_dict = {"title": "Mr.",
"first_name": " Timo",
"last_name": " Lanno"}
print(
to_full_name(name_dict)
)
print(
greet("Hello, ", name_dict)
)
q_eq_data = {"quadratic coefficient": 1,
"linear coefficient": 1,
"potential solution": 1,
"constant": 1}
print(
quadratic_equation(q_eq_data)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment