Welcome, guest | Sign In | My Account | Store | Cart

This small snippet came about as a result of this discussion on python-ideas, requesting a new syntax for dynamically reevaluating a function each time it is called.

This snippet implements a simple decorator to do so without added syntax.

Python, 49 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#! /usr/bin/env python3

from inspect import getsource
from functools import wraps

# get the globals out of the way
a, b, c = 0, 1, 2

def runtime(f):
	"""Evaluates the given function each time it is called."""
	# get the function's name
	name = f.__name__
	# and its source code, sans decorator
	source = remove_decorators(getsource(f))
	@wraps(f)
	def wrapped(*args, **kwargs):
		# execute the function's declaration
		exec(source)
		# since the above overwrites its name in the local
		# scope we can call it here using eval
		return eval("%s(*%s, **%s)" % (name, args, kwargs))
	return wrapped

def remove_decorators(source):
	"""Removes the decorators from the given function"""
	lines = source.splitlines()
	new_source = '\n'.join((line for line in lines if not line.startswith('@')))
	return new_source

@runtime
def example1(x, y=[]):
	y.append(x)
	return y

@runtime
def example2(x=a**2+2*b+c):
	return x

if __name__ == "__main__":
	print("Testing example1")
	print(example1(1))
	print(example1(2))
	print(example1(3))
	print()
	print("Testing example2 with default values")
	print(example2())
	print("Changing a to 5")
	a = 5
	print(example2())