[Baypiggies] Discussion for newbies/beginner night talks - test results
Shannon -jj Behrens
jjinux at gmail.com
Fri Feb 16 00:09:11 CET 2007
On 2/15/07, Chad Netzer <chad.netzer at gmail.com> wrote:
> On 2/15/07, Daniel Yoo <dyoo at cs.wpi.edu> wrote:
>
> > To make this easier, we should change the defintions so that these are
> > actual functions that can be compared functionally. For example:
> >
> > ##############################################
> > def holding_with_lists():
> > l = []
> > for x in range(0,100000):
> > l.append("abcdef")
> > return ''.join(l)
> >
> > def holding_naive():
> > l = ""
> > for x in range(0,100000):
> > l += "abcdef"
> > return l
> >
> > assert holding_with_lists() == holding_naive()
> > ##############################################
> >
> > Otherwise, without making sure these different implemenations return the
> > same result, we risk comparing apples to oranges. I suspect that's what's
> > happened here.
>
>
> Danny, in addition to your good advice, I'd also suggest not using
> range() in the loop, since Dennis was also intending to look at memory
> footprint. Use xrange(), or make a simple iterator instead.
>
> Dennis, you said in your example, "The final time.sleep(2000) is to
> allow time for garbage collection to reduce memory usage." However,
> that certainly will have no effect with CPython, nor do operating
> system memory allocators work that way. If I'm wrong about this,
> someone please enlighten me. You could try:
>
> gc.collect()
>
> but these simple examples probably don't have any unreachable memory
> cycles. In general, memory usage benchmarking can be a tricky
> undertaking, sometimes even for 'simple' examples.
I saw a talk at PyCon two years ago that said that Python would never
give memory back to the OS. That's probably changed, but I'd check
first.
I think this discussion is a bit of a red herring. I still think we
should focus on readability. If Dennis insists on using += instead of
a nice templating engine like Cheetah, and it turns out that
list.append uses less memory than +=, then let's remember that that
StringIO takes care of using a list internally. I suggest he do the
following since he seems to dislike triple quoted strings (which I
don't agree with):
from cStringIO import StringIO
buf = StringIO()
w = buf.write
w("String")
w("String %s bar." % name)
...
return w.getvalue()
Better yet, wrap that boilerplate in a function and use a "with"
statement to do it automatically ;)
As another contribution to perhaps make him happier, I submit this,
which I use to use before I switched to Cheetah:
===============================================
def evalstr(s, dollar="$"):
"""Evaluate a string with embedded python expressions.
This is a Python version of the function evalstr, which is used for
variable interpolation.
For instance,
a = 5
evalStr("I have $a$ dogs.")
will return
"I have 5 dogs."
The code between the $'s can be any valid Python expression. I'll just
basically do
str(eval(expression), yourGlobals, yourLocals)
Since eval is being used, the expression must return some value. To escape
$'s in s, just use $$ (even within expressions). To use a different
character than $, pass the desired character in the second (optional)
argument. If there are an odd number of $ symbols, a ValueError exception
will be raised. Here are some additional examples (assuming a = 5):
"My dog is $a$ years old." -> "My dog is 5 years old.",
"I have $$5.00" -> "I have $5.00",
"My $a$ year old dog has $$5.00" -> "My 5 year old dog has $5.00",
"My dog has $'$$%s.' % a$" -> "My dog has $5.",
"My dog has $'$$' + str(a) + '.'" -> ValueError exception,
"My dog is $a$.$" -> ValueError exception,
"$$ is a char." -> "$ is a char.",
"$a$ is a number." -> "5 is a number.",
"$a$" -> "5",
"$a" -> ValueError exception,
"I have a $$" -> "I have a $",
"" -> "",
"Spam" -> "Spam",
"$" -> ValueError exception,
"$ evalstr('I am #a#.', '#') $" -> "I am 5."
"""
# By the way, I'm sorry if this stuff is hard to read. If you
# can come up with something more elegant, I'd love to see it,
# but this is the best that I could come up with.
import string
import sys
inEv = 0 # Are we in eval mode (i.e. inside a single $)?
inDollar = 0 # We just got a dollar. We might be in an escape sequence.
ret = "" # This is the string we're returning.
tok = "" # The token we're currently working with.
stack = [] # All good languages are stack based ;)
i=j=0 # These are indexes into s.
# Grab the calling function's namespace. I can't find a nice
# way to do this other than manually generating an exception
# and surfing the traceback. As for performance, you can do
# this about 10000 times in a bit less than a second on my
# PIII 600 mhz system.
try:
1/0
except:
traceback = sys.exc_info()[2]
currFrame = traceback.tb_frame
prevFrame = currFrame.f_back
prevGlobals = prevFrame.f_globals
prevLocals = prevFrame.f_locals
# If they forget to close the $, raise a ValueError exception.
if string.count(s, dollar) % 2:
raise ValueError, "unmatched dollar symbol"
sLen = len(s)
while 1:
# Get next token.
j = i
if j==sLen:
tok = ""
elif s[j] == dollar:
tok = dollar
i = j+1
else:
while j<sLen and s[j]!=dollar: j=j+1
if j==sLen:
tok = s[i:]
i = sLen
else:
tok = s[i:j]
i = j
# Deal with receiving $'s (may call continue).
if tok == dollar:
if inDollar: inDollar = 0
else:
inDollar = 1
continue
# Deal with appending stuff to the stack or to ret.
if inDollar:
inEv = not inEv
inDollar = 0
if inEv: stack = stack + [tok]
else:
if len(stack) > 0:
ret = ret + \
str(eval(string.join(stack, ""),
prevGlobals,
prevLocals))
ret = ret + tok
stack = []
# Deal with end of string.
if tok == "": break
return ret
# I also have a C version of this if you want it.
===============================================
Happy Hacking!
-jj
--
http://jjinux.blogspot.com/
More information about the Baypiggies
mailing list