Re: Dreaming of new generation IDE

2010-02-11 Thread Francis Carr
 I can't believe the code editing situation today is in a such sorry
 state.
I can't believe an old coder is feeling so sorry for himself.


 Today, I tried to understand the twisted.web.client code and I found 3
 methods I couldn't find by who were called.

 I asked on the mailing list and they suggested me where they were
 called and that the tool for such thing is grep.

 So, you grep, you get a list of files, you open each one of them and
 keep scrolling and switching from one file to another... endlessly.
 Maybe I'm getting old, but I tend to get lost in the process.

Maybe the relevant lesson to be taken from Smalltalk is *not*
  put it all in one image
but instead
  write code to solve problems, e.g., reading code


I suggest defining a few shell functions to *automate* the search, for
example in zsh

function allf () {
  # Recursively find files with suffix matching comma-separated list
in $1.
  # For example, allf cpp,hpp finds all *.cpp and *.hpp.
  find . -type f | grep -E \.(${1//,/|})$
}

function src () {
  # Similar to allf, then search for a regex among the results.
  find . -type f -print0 | grep -zE \.(${1//,/|})$ | xargs -0 grep -
lE $2
}

function srcl () {
  # Similar to src (see above),
  # then search for a pattern among the results,
  # and pass matching files to less.
  src $1 $2 | xargs less -p $2
}


Smalltalk's images are cool.  But they are such a huge hammer, and
they impose so many additional requirements!  The costs outweigh the
cool.

 -- FC
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: python bijection

2009-12-03 Thread Francis Carr
[In re R. Hettinger's critiques]

 * it extends the language with arcane syntax tricks...
I think most of these in the current version of J. Bronson's bidict
can be left unused, or removed altogether.  In almost all cases, a
bidict should be accessed as an ordinary python dict.


 * we've already got one (actually two).
   The two dictionary approach...
Solutions such as bidict just automate the two-dict approach.

   ...sqlite3 provides another way...
In many many cases, using a dB (even a lightweight such as sqlite3) is
swatting the fly with a sledgehammer :-)


 Since bijections are symmetrical, they do not have an obvious
 direction (which is the primary key, the husband or the wife?).
I think this is easy to solve with a classmethod constructor that
produces a pair of linked dicts.  For example,
  husband2wife, wife2husband = bidict.makepair(('Fred', 'John'),
('Mary', 'Ruth'))
Obviously from the code this pair of bidicts are linked, and the
direction of each mapping is obvious from its name.  Metaprogramming
idioms like namedtuple are not required.


 * the semantics of a bijection aren't obvious:
      b['x'] = 'ex'      # first record:  ('x', 'ex')
      b['y'] = 'why'     # second record: ('y', 'why')
      b[:'why'] = 'x'    # do two records collapse into one?
 # is there an error?
Among the various critiques, I think this is the most significant.

When I was fiddling with my implementation, I was disturbed that the
code
  bidict[newKey] = oldValue
should have the subtle side-effect
  del bidict.inv[oldValue]

And there is a much stranger case.  Suppose bidict[key1]=val1 and
bidict[key2]=val2.  Then the code
  bidict[key1] = val2
should have the extremely subtle side-effects
  del bidict[key2]  # because val2 has been re-mapped
  del bidict.inv[val1]  # because key1 has been re-mapped
Blech!

I think there must be something better.  It would be interesting to
hear more opinions on the matter.

I propose raising ValueError when operating on one key would also
silently re-map or delete a different (key,value) pair.  This would
disallow both of the above cases.  To get the effect of the first
case, one would simply operate on the inverse mapping:
  bidict.inv[oldValue] = newKey
This should not be confusing: it's exactly how a python dict would
operate, except the linked mapping is altered to match, which is the
bookkeeping we want to automate in the first place.  To get the effect
of the second case, one would have to explicitly demand the side-
effects:
  del bidict[key2]
  del bidict.inv[val1]
  bidict[key1] = val2
Also not confusing.


 -- FC
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: python bijection

2009-11-27 Thread Francis Carr
I was really inspired by this discussion thread! :-)

After much tinkering, I think I have a simpler solution.  Just make
the inverse mapping accessible via an attribute, -AND- bind the
inverse of -THAT- mapping back to the original.  The result is a
python dict with NO NEW METHODS except this inverse-mapping
attribute.  I have posted it on code.activestate.com as a
href=http://code.activestate.com/recipes/576968/;Recipe 576968:
Flipdict -- python dict that also maintains a one-to-one inverse
mapping/a

 -- F. Carr
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Most efficient way to pre-grow a list?

2009-11-11 Thread Francis Carr
Hmmm.  I am trying some algorithms, and timeit reports that a
list.extend variant is fastest... WTH?!  Really this seems like it
must be a bug in implementing the [None]*x idiom.


As expected, appending one-at-a-time is slowest (by an order of
magnitude):
  % python -m timeit -s N=100 \
z=[2**32-1] \
while len(z)N: z.append(z[0])
  10 loops, best of 3: 223 msec per loop

A method based on list.extend doubling is much better:
  % python -m timeit -s N=100 \
z=[2**32-1] \
while len(z)N: z.extend(z[:N-len(z)])
  10 loops, best of 3: 22.2 msec per loop

The straightforward pythonic solution is better yet:
  % python -m timeit -s N=100 \
z=[2**32-1]*N
  100 loops, best of 3: 8.81 msec per loop

And the winner for speed is... over-allocate using list.extend, then
delete!
  % python -m timeit -s N=100 \
z=[2**32-1] \
while len(z)N: z.extend(z) \
del z[N:]
  100 loops, best of 3: 6.93 msec per loop


Using array.array('I') gives similar results:
  % python -m timeit -s import array -s N=100 \
z=array.array('I', [2**32-1]) \
while len(z)N: z.append(z[0])
  10 loops, best of 3: 278 msec per loop

  % python -m timeit -s import array -s N=100 \
z=array.array('I', [2**32-1]) \
while len(z)N: z.extend(z[:N-len(z)])
  100 loops, best of 3: 7.82 msec per loop

  % python -m timeit -s import array -s N=100 \
z=array.array('I', [2**32-1]) \
z=z*N
  100 loops, best of 3: 6.04 msec per loop

  % python -m timeit -s import array -s N=100 \
z=array.array('I', [2**32-1]) \
while len(z)N: z.extend(z) \
del z[N:]
  100 loops, best of 3: 4.02 msec per loop


These results appear to scale up.  I replaced N=100  2**20 with
N=2**25 and obtained the same relative ordering:
  % python -m timeit -s N=2**25 \
z=[2**32-1] \
while len(z)N: z.append(z[0])
  [Ctrl-C after a lng wait]

  % python -m timeit -s N=2**25 \
z=[2**32-1] \
while len(z)N: z.extend(z[:N-len(z)])
  10 loops, best of 3: 872 msec per loop

  % python -m timeit -s N=2**25 \
z=[2**32-1]*N
  10 loops, best of 3: 434 msec per loop

  % python -m timeit -s N=2**25 \
z=[2**32-1] \
while len(z)N: z.extend(z) \
del z[N:]
  10 loops, best of 3: 346 msec per loop


And just to see if array.array can help us when large amounts of
memory are in use:
  % python -m timeit -s import array -s N=2**25 \
z=array.array('I', [2**32-1]) \
while len(z)N: z.extend(z) \
del z[N:]
  10 loops, best of 3: 149 msec per loop
If speed is the overriding concern, then there's another factor of two
right there.


Python version and hardware info:
  Python 2.6.2 (release26-maint, Apr 19 2009, 01:58:18) [GCC 4.3.3] on
linux2
  12Gb RAM on a quad-core Intel Xeon 3Ghz CPU


 -- FC
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Doubley imported module caused devastating bug

2009-09-27 Thread Francis Carr
 I would like to propose that it be made impossible in the Python
 source to import two instances of the same module.

A fully-automatic solution is more difficult than it might seem at
first:
  http://www.python.org/dev/peps/pep-0328/
But there is a simple code-discipline solution: never ever use
relative imports, even between code in the same package.

We got bit by double-imports (a mix of relative, absolute, and even
cross-imports A import B and B import A) early on in one of our
projects.  The symptom was that the imported module would be
initialized *twice*, once for a relative import and once for an
absolute.  This is not a happy situation for pseudo-singletons like
the logging module --- esp. if one is hacking the internals! :-)  We
no longer use relative imports *EVER*, even within the same package.

Perhaps Perforce is doing something tricky with scoping or importing,
and you've just managed to stumble across this trickiness because of a
double-import.  Good luck, these things are a bugger to debug.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: itertools.intersect?

2009-06-22 Thread Francis Carr
On Jun 11, 6:23 pm, Mensanator mensana...@aol.com wrote:
 Removing the duplicates could be a big problem.

It is fairly easy to ignore duplicates in a sorted list:
pre
from itertools import groupby
def unique(ordered):
Yield the unique elements from a sorted iterable.

for key,_ in groupby(ordered):
yield key
/pre

Combining this with some ideas of others, we have a simple, complete
solution:
pre
def intersect(*ascendingSeqs):
Yield the intersection of zero or more ascending iterables.

N=len(ascendingSeqs)
if N==0:
return

unq = [unique(s) for s in ascendingSeqs]
val = [u.next() for u in unq]
while True:
for i in range(N):
while val[i-1]  val[i]:
val[i] = unq[i].next()
if val[0]==val[-1]:
yield val[0]
val[-1] = unq[-1].next()
/pre

This works with empty arg-lists; combinations of empty, infinite and
finite iterators; iterators with duplicate elements; etc.  The only
requirement is that all iterators are sorted ascending.

 -- FC
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Self function

2009-05-07 Thread Francis Carr
Scheme is arguably the programming language with the most support for
recursion, including the most complete support for tail-call
optimization, constructs like letrec to define collections of
multiply-recursive functions (which get used very frequently -- by no
means is it an uncommon situation, as you suggest in your initial
post), and hardly any iterative loops.  Yet -- scheme does not provide
out-of-the-box support for your proposed let-a-function-implicitly-
refer-to-itself idea.  This suggests that the idea itself runs
counter to more important aspects of a programming language.

In the special case of a self-recursive function, you would like re-
naming to just work.  Out of morbid curiosity, I am compelled to
ask... why do you expect that re-naming anything --- a function, a
class, a module, a variable, anything --- in just one place but not
all the others should ever, under any circumstances, just work ?
--
http://mail.python.org/mailman/listinfo/python-list