Showing posts with label hack. Show all posts
Showing posts with label hack. Show all posts

20080225

Batch-fu

I don't know how many avid windows batchers are out there ( I was one some years ago ), but perhaps a few of you can use / be horrified by this little helper. Ever get annoyed because you can't easily reuse functions between scripts since they'll stomp all over each others environment variables? Probably not. Just in case, here's how to create lexically scoped batch file functions.

::#
:ServerName_Service
setlocal

:: blah blah do anything to namespace blah

::now pass the full name / status back out of the setlocal
for /F "usebackq tokens=1,2 delims=~" %%a in (`echo.%ServiceName%~"%Status%"`) do (
endlocal
set CACHE~%%a=%%b
)
goto :eof

Tada!

Even better if you structure them such that the first argument is the name of the variable to receive the value from the function call and then write your exit similar to this :

::now pass the full name / status back out of the setlocal
for /F "usebackq tokens=1,2 delims=~" %%a in (`echo.%ServiceName%~"%Status%"`) do (
endlocal
set %1=%%b
)

BTW, I don't really recommend writing large programs in batch, but if draconian network policies make it all you've got, good luck.

Remember that it is two phase, first variable expansion happens, then execution occurs. Execution of lines starting with `:' makes these lines into labels. Lines that start `::' are label errors and dropped ( making for better comments than rem, which executes and freaks out all to hell if special characters are in its argument list / comment area ). Lines starting `%%en_var%%' where the environment variable `en_var' has the value `::' are label errors and dropped. ( This can be used to great effect. I can't take credit for this hack though. I found it on Rob van der Woude's scripting site ).

20071129

A context manager for temporary memoization.

This is very much a fragile hack at the moment. It's an interesting idea I think. I was disappointed when I initially found that the with_statement syntax does not restore the value of the `as var` upon completion.

This made doing something along the lines of


with temporarily_memoized( func ) :
for datum in data :
func( datum )

unattainable.

Well, just a lot hackier actually.

Thus temporarily_memoized( ... ) was born :

#!/usr/bin/python

# a context manager for temporarily turning any function into
# a memoized version of itself.

from __future__ import with_statement
import contextlib , sys , types

def memoize ( func ) :
""" In haskell mutability must be handled explicitly.
Only fair that Python do the same to transparent functionality
"""
remembered = {}
def memoized ( *args ) :
""" memoized version of function """
if args in remembered :
return remembered[ args ]
else :
new = func( *args )
remembered[ args ] = new
return new
return memoized

@contextlib.contextmanager
def temporarily_memoized ( func ) :
""" memoize the given function for the duration of this block
save anything in the local variables that gets in the way of
using this so that it can be restored afterward , the memoized
version is found in the locals. use on actual functions only.
no members. """

# this is being called, there has to be a frame above it
frame = sys._getframe().f_back.f_back

if func.func_name in frame.f_locals :
f = frame.f_locals[ func.func_name ]
frame.f_locals[ func.func_name ] = memoize( func )
try :
# this hack replaces whatever in the local scope
# has the name of the variable. if you try to use
# the 'as whatever' portion of the syntax , you
# are doing it wrong
yield None
finally :
frame.f_locals[ f.func_name ] = f
else :
frame.f_locals[ func.func_name ] = memoize( func )
try :
yield None
finally :
del frame.f_locals[ func.func_name ]

def fib(n):
""" biggus fibbus """
if n == 0 or n == 1:
return n
else:
return fib(n-1) + fib(n-2)

if __name__ == '__main__' :
print fib.__doc__
with temporarily_memoized( fib ) :
print fib.__doc__
for i in xrange( 36 ) :
print "n=%d => %d" % (i, fib(i))
print fib.__doc__
print fib.__doc__


I've played around with replacing the func_code and related variables in order to create a true proxy, but the requirement that the func_code and func_closure agree exactly on the number of local variables and that they refuse to set independently or be tricked into simultaneous setting by calling types.FunctionType.__init__( target , proxy-code , ... ) has thwarted my attempts at this. I considered creating a variety of proxy functions each requiring a different number of free variables and then selecting the appropriate one, which would probably work, but it seems too much the wrong way to do things.

About Me

(2) the subculture of the compulsive programmer, whose ethics prescribe that one silly idea and a month of frantic coding should suffice to make him a life-long millionaire. --ewd1036