Advertisement
Guest User

Untitled

a guest
Jul 20th, 2019
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.25 KB | None | 0 0
  1. ## Description: Decorator that enforces purity on a function. Think of it as declaring a const function in C++.
  2. ## Why: Pure functions ensure that certain inputs always result in certain outputs, under the same transformations.
  3. ## Working with pure functions can ease your development because you never have to stop and worry and check
  4. ## whether using a certain function will implicitly mutate something. Things change only when YOU want them
  5. ## explicitly to change, via: `new_thing = transformation(old_thing)`.
  6. ## Usage: See examples below. You can run the small tests with: `python pure_function_decorator.py`.
  7. ## Python version: 3.6+ (you can adapt for previous versions by not using the f'' format strings and using python2 prints)
  8. ## Author: Michele Piccolini
  9.  
  10. from functools import wraps
  11.  
  12. def pure(func):
  13. @wraps(func) # maintain func's docstring
  14. def wrapped(*args, **kwargs):
  15. # run function on copy of arguments, so that they are not mutated even if func turns out to be impure
  16. import copy
  17. proxy_args = copy.deepcopy(args)
  18. proxy_kwargs = copy.deepcopy(kwargs)
  19. result = func(*proxy_args, **proxy_kwargs)
  20. # check purity
  21. for proxy_arg, arg, idx in zip(proxy_args, args, range(len(args))):
  22. if proxy_arg != arg:
  23. raise Exception(f"Function '{func.__name__}' is not pure, at parameter n. {idx}.")
  24. # if not all([proxy_arg == arg for proxy_arg, arg in zip(proxy_args, args)]):
  25. # raise Exception(f"Function {func.__name__} is not pure.")
  26. for arg_name in kwargs.keys():
  27. if proxy_kwargs[arg_name] != kwargs[arg_name]:
  28. raise Exception(f"Function '{func.__name__}' is not pure, at named parameter '{arg_name}'.")
  29. return result
  30. return wrapped
  31.  
  32. # test
  33. if __name__ == '__main__':
  34. @pure
  35. def purefunc(a):
  36. """A pure function - does not modify its inputs"""
  37. print(a)
  38. print("\n>Testing a pure function...")
  39. mystr = 'hello'
  40. try: purefunc(mystr)
  41. except Exception as e: print(e)
  42. else: print(">OK")
  43.  
  44. @pure
  45. def falseimpurefunc(b):
  46. """A function that could seem impure but it is not,
  47. since numbers are immutable in python (i.e. when you
  48. modify them you are always working on copies, as in C)"""
  49. b += 2
  50. print("\n>Testing a pure function (it would be impure if it weren't acting on immutable variables)...")
  51. mynum = 0
  52. try: falseimpurefunc(mynum)
  53. except Exception as e: print(e)
  54. else: print(">OK")
  55.  
  56. @pure
  57. def impurefunc(L):
  58. """An impure function"""
  59. L.append(0)
  60. print("\n>Testing an impure function...")
  61. mylist = []
  62. try: impurefunc(mylist)
  63. except Exception as e:
  64. print(e)
  65. print(f"Argument before was: {[]}, now is: {mylist}.\n"
  66. f"The @pure decorator prevented it from being mutated!")
  67. else: print(">OK")
  68.  
  69. @pure
  70. def impurefunc2(a, L=[]):
  71. print(a)
  72. L.append(0)
  73. print("\n>Testing an impure function (impure on named argument)...")
  74. try: impurefunc2(mystr, L=mylist)
  75. except Exception as e:
  76. print(e)
  77. print(f"Named argument before was: L={[]}, now is: {mylist}.\n"
  78. f"The @pure decorator prevented it from being mutated!")
  79. else: print("OK")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement