Created
March 23, 2016 09:54
-
-
Save not-much-io/67dfa5d160acfd8ecdfb 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 destructuring import destructure | |
from unittest import TestCase, main | |
from types import FunctionType | |
""" | |
This is just a proposition on how destructuring could be done in Python. | |
This is just an exercise, the result itself is not meant to be pragmatic for everyday Python code. | |
Unpacking is a limited form of destructuring: | |
a, b, c = [1, 2, 3] | |
The syntax I chose used parameter annotations and a decorator, as these were easily available for use: | |
@destructure | |
def foo(d: <some destructuring expression>) | |
The "perfect" (readability wise) solution and use case would be something like this: | |
d = {"a": 0, "b": 1, "c": 2} | |
def foo(a, b, c = d): | |
return a + b + c | |
foo(d) => 3 | |
The regular way is: | |
d = {"a": 0, "b": 1, "c": 2} | |
def foo(d): | |
return d["a"] + d["b"] + d["c"] | |
foo(d) => 3 | |
There are many forms of destructuring, these test cover the basic form: | |
d = {"a": 0, "b": 1} | |
def foo(d: ("a", "b")): | |
return a + b | |
foo(d) => 1 | |
Maybe you have a better idea how to do this? :) | |
NOTE: | |
It is probably "impossible" to do this cleanly as Scoped names are determined at compile time in Python. | |
For more destructuring syntax example see: https://gist.github.com/john2x/e1dca953548bfdfb9844 (code is in Clojure) | |
""" | |
class TestDestructuringBasic(TestCase): | |
simple_dict = {"key1": 10, | |
"key2": 1} | |
@staticmethod | |
@destructure | |
def sum_key1_and_key2(d: ('key1', 'key2')): | |
""" | |
Destructure the dict d, by getting out these keys and | |
putting them inside variables with the same name. | |
""" | |
return key1 + key2 | |
def test_simple_tuple_expr(self): | |
val_sum = self.sum_key1_and_key2(self.simple_dict) | |
self.assertEqual(val_sum, 11) | |
class TestDestructuringAdvanced(TestCase): | |
object_dict = {"obj1": 10, | |
"obj2": "Test String", | |
"obj3": lambda x: x} | |
@staticmethod | |
@destructure | |
def types_seq(first_type: type, # Type hint | |
cd: ("obj1", "obj2", "obj3"), # Destructuring | |
regular_param, # Regular positional argument | |
*args) -> list: # Variable number arguments + return type (unlikely to be affected) | |
cd_types = [type(o) for o in (obj1, obj2, obj3)] | |
return [first_type] + cd_types + [regular_param] + list(args) | |
def test_tuple_advanced(self): | |
# Tests if: | |
# Type hints continue working | |
# Destructuring works in random position | |
# Regular positional parameters are unaffected | |
# Variable number arguments are unaffected | |
try: | |
res = self.types_seq(tuple, | |
self.object_dict, | |
list, | |
int, str, str) | |
except NameError: | |
raise AssertionError("A NameError was raised, destructured vars" | |
" were probably not made available to function scope") | |
self.assertEqual(res, [tuple, | |
int, str, FunctionType, | |
list, | |
int, str, str]) | |
# ToDo test destructuring with dictionary expression | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment