Created
February 19, 2016 11:40
-
-
Save not-much-io/dc2b098528770658c667 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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