self modifying code

Robin Becker robin at NOSPAMreportlab.com
Mon May 1 11:44:03 CEST 2006


taleinat at gmail.com wrote:
........
> 
> What have we gained from this? Two major advantages:
> * no ugly 'global' statement
> * no reliance on the function's name

I don't dispute either of the above, however, the actual overhead of 
your approach appears to be much higher (see below) probably because it 
has two function calls instead on one to get the answer.




> 
> And now you can easily create such functions forever using this class
> to abstract away the ugly implementation ;)
....... yes indeed

######file dingo.py
class InitializingFunction(object):
	def __init__(self, init):
		def initializer(*args, **kw):
			self.func = init()
			return self(*args, **kw)
		self.func = initializer
	def __call__(self, *args, **kw):
		return self.func(*args, **kw)

def init():
	data = 42
	def foo(arg):
		return arg+data
	return foo
a = InitializingFunction(init)

def b(arg):
	global b
	data = 42
	def b(arg):
		return arg+data
	return b(arg)
######

Testing with timeit
C:\Tmp>\Python\lib\timeit.py -s"from dingo import a;a(0)" a(1)
100000 loops, best of 3: 2.25 usec per loop

C:\Tmp>\Python\lib\timeit.py -s"from dingo import b;b(0)" b(1)
1000000 loops, best of 3: 0.52 usec per loop

so since the simple function is fairly trivial the overhead seems to be 
around 4 times that of the weird approach.

The global naming stuff is pretty flaky and relies on the way names are 
looked up; in particular it seems as though references to the original 
global will be held at least throughout a single statement. If the first 
call is "print b(0),b(1)" then b is initialised twice.

This 'masterpiece of obfuscation' ;) gets round that problem, but is 
pretty odd to say the least and still relies on knowing the class name.

class Weird(object):
	@staticmethod
	def __call__(arg):
		data = 42
		def func(arg):
			return arg+data
		Weird.__call__ = staticmethod(func)
		return func(arg)
c = Weird()

it is still more expensive than b, but not by much

C:\Tmp>\Python\lib\timeit.py -s"from dingo import c;c(1)" c(1)
1000000 loops, best of 3: 0.709 usec per loop

-- 
Robin Becker



More information about the Python-list mailing list