Re: shuffling elements of a list

2006-05-31 Thread David C.Ullrich
On 30 May 2006 21:53:32 -0700, "greenflame" <[EMAIL PROTECTED]>
wrote:

>Thank you all for all of your help. Also I got the shuffle function to
>work. Do not worry I will be back soon with more shuffling! However, I
>do not quite understand this DSU that you mention, although it looks
>useful.

I didn't see any DSU in his post, although I didn't read
it very carefully. DSU is "Decorate Sort Undecorate" -
it's an idiom for efficient sorting. Say you have a list
and you want to sort it using some custom compare function.
That can be very slow. Sorting a list with the builtin
comparison is much faster.

DSU is a trick that lets you use the fast builtin comparison
to sort according to a custom compare. Say you have a list 
[x,y,z], these objects have an attribute "a", and you want
to sort on the "a" field. You "decorate" the list, 
constructing a new list of tuples 

   [(x.a, x), (y.a, y), (z.a, z)]

You sort the decorated list using the standard
sort(). Tuples get compared lexicographically,
so this sorts on the "a" field. Then you
"undecorate" the sorted list, stripping
off the first element of each tuple.

**

That's DSU for _sorting_ a list. I read about this, thought
it was pretty neat. I thought that the fact that you
could use the same trick for _shuffling_ a list was
my idea, gonna make me rich and famous. I guess I'm
not the only one who thought of it. Anyway, you can
use DSU to _shuffle_ a list by decorating the list
with random numbers.

In fairly old-fashioned Python:

from random import random

def shuffle(data):
  decorated = map(lambda x: (random(), x), data)
  decorated.sort()
  return map(lambda x: x[1], decorated)

print shuffle(range(10))

This prints

[4, 2, 7, 8, 9, 3, 5, 1, 6, 0]

. Seems kinda neat - I have no idea how the efficiency
compares with the standard sort of "bubble shuffle"
you were trying to use in your OP, but the point is
that various off-by-one errors simply don't come up.

(The same thing in extremely awful Python, in case
you're mystified by map and lambda:

from random import random

def shuffle(data):
  decorated = []
  for x in data:
decorated.append((random(), x))
  decorated.sort()
  res = []
  for x in decorated:
res.append(x[1])
  return res

.)



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: shuffling elements of a list

2006-05-31 Thread David C.Ullrich
On Wed, 31 May 2006 12:17:11 +0200, Sybren Stuvel
<[EMAIL PROTECTED]> wrote:

>David C  Ullrich enlightened us with:
>> I thought that the fact that you could use the same trick for
>> _shuffling_ a list was my idea, gonna make me rich and famous. I
>> guess I'm not the only one who thought of it. Anyway, you can use
>> DSU to _shuffle_ a list by decorating the list with random numbers.
>
>This is often done in database queries that need to randomize the data
>;-)

Huh. Gotta find a good patent attorney.

>Sybren




David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: shuffling elements of a list

2006-06-01 Thread David C.Ullrich
On Wed, 31 May 2006 23:05:14 +0200, Fredrik Lundh
<[EMAIL PROTECTED]> wrote:

>Roger Miller wrote:
>
>> DSU seems like a lot of trouble to go through in order to use an O(n
>> log n) sorting algorithm to do what can be done in O(N) with a few
>> lines of code.  The core code of random.shuffle() shows how easy it is
>> to do it right:
>> 
>> for i in reversed(xrange(1, len(x))):
>> # pick an element in x[:i+1] with which to exchange x[i]
>> j = int(random() * (i+1))
>> x[i], x[j] = x[j], x[i]
>
>easy to do it right?  you know, the main reason for adding shuffle to 
>the standard library was that its way too easy to get it wrong.

Heh. And I thought it was just me.

_I_ find it easy to get the "limits" wrong, even though I have
the idea of the algorithm perfectly straight. Better yet is the
number of times I've seen a simply wrong algorithm posted online:

>see e.g. this thread: http://tinyurl.com/ppgzq

Good example, because we know that EMF is not dumb. I've seen
the same algorithm many times - the best example is

http://www.cigital.com/papers/download/developer_gambling.php

Some poker site posted the simply-wrong algorithm in an effort
to convince people that their decks were properly shuffled!




David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: shuffling elements of a list

2006-06-02 Thread David C.Ullrich
On Thu, 01 Jun 2006 03:25:23 -0700, Erik Max Francis <[EMAIL PROTECTED]>
wrote:

>David C. Ullrich wrote:
>
>> Good example, because we know that EMF is not dumb. I've seen
>> the same algorithm many times - the best example is ...
>
>Man, an error made _six years ago_ and people are still bringing it up ...

Sorry. Happens to me on sci.math all the time. The point really
wasn't that you were so dumb, the point was just the opposite.
(_I_ didb't bring it up, btw - I would never have known about
it if FL hadn't pointed it out.)




David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


CSV(???)

2007-02-23 Thread David C.Ullrich
Is there a csvlib out there somewhere?

And/or does anyone see any problems with
the code below?

What csvline does is straightforward: fields
is a list of strings. csvline(fields) returns
the strings concatenated into one string
separated by commas. Except that if a field
contains a comma or a double quote then the
double quote is escaped to a pair of double
quotes and the field is enclosed in double
quotes.

The part that seems somewhat hideous is
parsecsvline. The intention is that
parsecsvline(csvline(fields)) should be
the same as fields. Haven't attempted
to deal with parsecsvline(data) where
data is in an invalid format - in the
intended application data will always
be something that was returned by
csvline. It seems right after some
testing... also seems blechitudinous.

(Um: Believe it or not I'm _still_ using
python 1.5.7. So comments about iterators,
list comprehensions, string methods, etc
are irrelevent. Comments about errors in
the algorithm would be great. Thanks.)

The code:

from string import replace, join

def csvescape(s):
  if ',' in s or '"' in s or '\n' in s:
res = replace(s, '"', '""')
return '"%s"' % res
  else:
return s

def csvline(fields):
  return join(map(csvescape, fields), ',')

class indexedstring:
  def __init__(self, s):
self.s = s
self.index = 0

  def current(self):
return self[self.index]

  def inc(self):
self.index = self.index + 1

  def next(self):
self.inc()
return self.current()

  def __getitem__(self, j):
return self.s[j]

  def __len__(self):
return len(self.s)

  def eos(self):
return self.index >= len(self)

  def lookahead(self):
return self[self.index + 1]

  def getfield(self):
if self.eos():
  return None
if self.current() == '"':
  return self.quotedfield()
else:
  return self.rawfield()

  def rawfield(self):
"""Read until comma or eos."""
start = self.index
while not (self.eos() or (self.current() == ',')):
  self.inc()

res = self.s[start:self.index]

self.inc()

return res

  def quotedfield(self):
"""Read until '",' or '" followed by eos.
Replace "" in result with "."""

start = self.index

while 1:
  self.inc()
  if self.current() == '"':
self.inc()
if (self.eos() or (self.current()==',')):
  break

res = self.s[start + 1:self.index - 1]

self.inc()

return replace(res, '""', '"') 

def parsecsvline(csvline):
  """Inverts csvline(). Assumes csvline is valid, ie
  is something as returned by csvline(); output undefined
  if csvline is in invalid format"""

  s = indexedstring(csvline)
  res = []

  while not s.eos():
   res.append(s.getfield())

  return res



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: CSV(???)

2007-02-24 Thread David C.Ullrich
On Fri, 23 Feb 2007 11:43:24 + (UTC), Philipp Pagel
<[EMAIL PROTECTED]> wrote:

>David C. Ullrich <[EMAIL PROTECTED]> wrote:
>> Is there a csvlib out there somewhere?
>
>How about csv in the standard library?
>
>> (Um: Believe it or not I'm _still_ using
>> python 1.5.7.
>
>I have no idea if csv was part of the standard library backin those
>days...

Nope.

>But even if not: either upgrade to something less outdated 

Thanks. Actually, for reasons I could explain if you really
wanted to know, going to 2.x would actually cost me some
money. Since I'm not getting paid for this...

>or see if you
>can get todays csv to work with the oldtimer.
>
>cu
>   Philipp




David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: CSV(???)

2007-02-24 Thread David C.Ullrich
On 23 Feb 2007 11:51:57 GMT, nmp <[EMAIL PROTECTED]> wrote:

>Op Fri, 23 Feb 2007 11:45:54 +, schreef nmp:
>
>> Op Fri, 23 Feb 2007 05:11:26 -0600, schreef David C. Ullrich:
>> 
>>> Is there a csvlib out there somewhere?
>> 
>> Hey, cool! I am just beginning with Python but I may already be able to
>> help you ;)
>
>Oops I missed the bit where you said you were using that very old Python
>version...

No problem. Actually if there were a csv.py in my version I would
have found it before posting, but you didn't know that.




David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: CSV(???)

2007-02-24 Thread David C.Ullrich
On 23 Feb 2007 19:13:10 +0100, Neil Cerutti <[EMAIL PROTECTED]> wrote:

>On 2007-02-23, David C  Ullrich <[EMAIL PROTECTED]> wrote:
>> Is there a csvlib out there somewhere?
>>
>> And/or does anyone see any problems with
>> the code below?
>>
>> [...]
>>
>> (Um: Believe it or not I'm _still_ using python 1.5.7. So
>> comments about iterators, list comprehensions, string methods,
>> etc are irrelevent. Comments about errors in the algorithm
>> would be great. Thanks.)
>
>Two member functions of indexedstring are not used: next and
>lookahead. __len__ and __getitem__ appear to serve no real
>purpose.

Hey, thanks! I didn't realize that using an object with
methods that were never called could cause an algorithm
to fail... shows how much I know.

(Seriously, all I really wanted to know was whether anyone
noticed something I overlooked, so that 
parsecsvline(csvline(fields)) might under some condition
not come out the same as fields...)

>> def parsecsvline(csvline):
>>   """Inverts csvline(). Assumes csvline is valid, ie
>>   is something as returned by csvline(); output undefined
>>   if csvline is in invalid format"""
>>
>>   s = indexedstring(csvline)
>>   res = []
>>
>>   while not s.eos():
>>res.append(s.getfield())
>>
>>   return res
>
>You'll be happy to know that iterators and list comprehensions
>will make your code better after you upgrade. ;-)

Uh, thanks again. You're right, knowing that makes me so happy
I could just burst.

>In the meantime, I think your (relative lack of) error handling
>is OK. GIGO, as they say (garbage in, garbage out).

_I_ don't think it's ok.

But (i) the code I posted was not supposed to be the final
version! It was a preliminary version, posted hoping that
someone would notice any errors in the _algorithm_ that
existed. (ii) in the intended application parsecsvline
will only be applied to the output of csvline, so if
the former is indeed a left inverse of the latter there
should be no error unless something else has already
gone wrong elsewhere. Not that that makes it ok...



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: CSV(???)

2007-02-24 Thread David C.Ullrich
On 23 Feb 2007 07:31:35 -0800, "John Machin" <[EMAIL PROTECTED]>
wrote:

>On Feb 23, 10:11 pm, David C. Ullrich <[EMAIL PROTECTED]>
>wrote:
>> Is there a csvlib out there somewhere?
>
>I can make available the following which should be capable of running
>on 1.5.2 -- unless they've suffered bitrot :-)
>
>(a) a csv.py which does simple line-at-a-time hard-coded-delimiter-etc
>pack and unpack i.e. very similar to your functionality *except* that
>it doesn't handle newline embedded in a field. You may in any case be
>interested to see a different way of writing this sort of thing: my
>unpack does extensive error checking; it uses a finite state machine
>so unexpected input in any state is automatically an error.

Actually a finite-state machine was the first thing I thought of.
Then while I was thinking about what states would be needed, etc,
it ocurred to me that I could get something working _now_ by
just noticing that (assuming valid input) a quoted field
would be terminated by '",' or '"[eos]'.

A finite-state machine seems like the "right" way to do it,
but there are plenty of other parts of the project where
doing it right is much more important - yes, in my experience
doing it "right" saves time in the long run, but that
finite-state machine would have taken more time 
_yesterday_.

>(b) an extension module (i.e. written in C) with the same API. The
>python version (a) imports and uses (b) if it exists.
>
>(c) an extension module which parameterises everything including the
>ability to handle embedded newlines.
>
>The two extension modules have never been compiled & tested on other
>than Windows but they both should IIRC be compilable with both gcc
>(MinGW) and the free Borland 5.5 compiler -- in other words vanilla C
>which should compile OK on Linux etc.
>
>If you are interested in any of the above, just e-mail me.

Keen.

>>
>> And/or does anyone see any problems with
>> the code below?
>>
>> What csvline does is straightforward: fields
>> is a list of strings. csvline(fields) returns
>> the strings concatenated into one string
>> separated by commas. Except that if a field
>> contains a comma or a double quote then the
>> double quote is escaped to a pair of double
>> quotes and the field is enclosed in double
>> quotes.
>>
>> The part that seems somewhat hideous is
>> parsecsvline. The intention is that
>> parsecsvline(csvline(fields)) should be
>> the same as fields. Haven't attempted
>> to deal with parsecsvline(data) where
>> data is in an invalid format - in the
>> intended application data will always
>> be something that was returned by
>> csvline.
>
>"Always"? Famous last words :-)

Heh. 

Otoh, having read about all the existing variations
in csv files, I don't think I'd attempt to write
something that parses csv provided from an
external source.

>> It seems right after some
>> testing... also seems blechitudinous.
>
>I agree that it's bletchworthy, but only mildly so. If it'll make you
>feel better, I can send you as a yardstick csv pack and unpack written
>in awk -- that's definitely *not* a thing of beauty and a joy
>forever :-)
>
>I presume that you don't write csvline() output to a file, using
>newline as a record terminator and then try to read them back and pull
>them apart with parsecsvline() -- such a tactic would of course blow
>up on the first embedded newline. 

Indeed. Thanks - this is exactly the sort of problem I was hoping
people would point out (although in fact this one is irrelevant,
since I already realized this). In fact the fields will not
contain linefeeds (the data is coming from 
on an html form, which means that unless someone's _trying_
to cause trouble a linefeed is impossible, right? Regardless,
incoming data is filtered. Fields containing newlines are
quoted just to make the thing usable in other situations - I
wouldn't use parsecsvline without being very careful, but there's
no reason csvline shouldn't have general applicability.) And in 
any case, no, I don't intend to be parsing multi-record csv files.

Although come to think of it one could modify the above
to do that without too much trouble, at least assuming
valid input - end-of-field followed by linefeed must
be end-of-record, right?

>So as a matter of curiosity, where/
>how are you storing multiple csvline() outputs?

Since you ask: the project is to allow alumni to
store contact information on a web site, and then
let office staff access the information for various
purposes. So each almunus' data is stored as a
csvline in an anydbm "database" - when someone in
the office requests the information it's dumped
into a csv file, the idea being that the office
staff opens that in Excel or whatever.

(Why not simply provide a suitable interface
to the data instead of just giving them the
csv file? So they can use the data in ways I
haven't anticipated. Why not give them access
to a real database? They know how to use Excel.

I do think I'll provide a few access thingies
in addition to the csv file, for ex

Multiple Version Install?

2006-05-04 Thread David C.Ullrich
Would there be issues (registry settings, environment
variables, whatever) if a person tried to install
versions 1.x and 2.x simultaneously on one Windows
system? Windows 98, if it matters.

(I can handle the file associations with no problem.)

Thanks.

**

If anyone feels like pointing out that there's simply
no reason to want to keep 1.x after installing the
current version: By all means talk me into that!

The problem is not that I'm concerned about backwards
compatibility of Python code. The problem is that I
use Python embedded in various Delphi programs,
including a "DIDE" that I use really a lot, via
a certain set of Delphi "components". These components
don't seem to work with 2.x. Presumably the PyDelphi
people have new versions of the components that do
work with Python 2.x. These presumably use much
newer versions of Delphi than what I have. A new
version of Delphi is not free... If I could use
Python 2.x when I need to while continuing to
use 1.x the way I have been for things that 
don't need 2.x that would be convenient.



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Multiple Version Install?

2006-05-04 Thread David C.Ullrich
On Thu, 4 May 2006 16:17:57 +0200, "Fredrik Lundh"
<[EMAIL PROTECTED]> wrote:

>David C.Ullrich wrote:
>
>> Would there be issues (registry settings, environment
>> variables, whatever) if a person tried to install
>> versions 1.x and 2.x simultaneously on one Windows
>> system? Windows 98, if it matters.
>>
>> (I can handle the file associations with no problem.)
>
>in general, no.

Excellent. Thanks.

>(I usually have about a dozen Python's, or more, on most of my
>windows boxes)
>
>however, applications that look in the registry may only find the
>last one you've installed.
>
> 
>
>




David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Multiple Version Install?

2006-05-05 Thread David C.Ullrich
On Thu, 4 May 2006 13:19:46 -0400, "Tim Peters" <[EMAIL PROTECTED]>
wrote:

>[David C.Ullrich]
>> Would there be issues (registry settings, environment
>> variables, whatever) if a person tried to install
>> versions 1.x and 2.x simultaneously on one Windows
>> system? Windows 98, if it matters.
>>
>> (I can handle the file associations with no problem.)
>
>There are generally no issues 

One more thing you Python guys got right.

Just curious: How does pythonxx.dll determine things
like where to find the standard library? That's the
sort of thing I'd feared might cause confusion...

>beyond file associations. 

Which is no problem. Either you add "Run 1.x" and "Run 2.x"
to the context menu or you associate .py with a tiny
windowless .exe that emulates the UNIX thing, reading
the first line of the file and then running the
appropriate python.exe.

(Before I tried it I thought that second might slow
down startup, but evidently even Windows is willing
to load a program quickly if it's small enough - I've
never noticed any delay.)

> On Windows,
>Python versions i.j.k and i'.j'.k' coexist happily so long as i != i'
>or j != j'.  For example, I currently have the python.org-released
>Pythons 2.2.3, 2.3.5, and 2.4.3 installed on my Windows box. 

I wouldn't have bothered explaining why I cared except that
I was under the impression that the official line was that
if I wanted to use two versions I must be doing something
wrong. I guess not, fine.

> It would
>be a challenge only if I wanted, say, 2.4.2 and 2.4.3 installed
>simultaneously.
>
>Another possible issue is that whenever the major or minor version
>numbers (i or j) change on Windows, you also need to install matching
>versions of any 3rd party extensions you want.  The major and minor
>version numbers appear in the _name_ of the core Python DLL (like
>python23.dll and python24.dll), and extensions with C code must be
>compiled to link with the correct version of the Python DLL.

No problem with the one emedding I want to use - no recompile
needed, it requires that I simply set the name of the dll as
a "property" of the "engine".

(But simply setting dllname = "python2whatever.dll" gives
errors about functions not found. Is this just me doing
something wrong or did functions with certain names
actually disappear? Not a complaint, just curious.)

>> If anyone feels like pointing out that there's simply
>> no reason to want to keep 1.x after installing the
>> current version: By all means talk me into that!
>
>If you've been using extensions with 1.j.k, then as above they have no
>chance of working with 2.j'.k' bejore you install 2.j' versions of
>those extensions.  That's a good reason to keep an old version.
>
>There have been thousands of bugfixes and language enhancements since
>1.j.k too, and not all are 100% backward-compatible.
>
>In all, best advice is to keep the old version around until you're
>sure you no longer need it.
>
>> The problem is not that I'm concerned about backwards
>> compatibility of Python code. The problem is that I
>> use Python embedded in various Delphi programs,
>> including a "DIDE" that I use really a lot, via
>> a certain set of Delphi "components". These components
>> don't seem to work with 2.x. Presumably the PyDelphi
>> people have new versions of the components that do
>> work with Python 2.x. These presumably use much
>> newer versions of Delphi than what I have. A new
>> version of Delphi is not free... If I could use
>> Python 2.x when I need to while continuing to
>> use 1.x the way I have been for things that
>> don't need 2.x that would be convenient.
>
>That should work fine.  I don't know about PyDelphi, but found what
>appears to be a still-active discussion list:
>
>http://groups.yahoo.com/group/pythonfordelphi/
>
>The theoretical joy of open source is that if they _don't_ support the
>Python+Delphi combo you have, you can fix that yourself ;-)

Crossed my mind, but only briefly - "theoretically" seems right.
(One of the big improvements in later versions of Delphi is
reference-counted/garbage-colleted dynamically sized arrays.
Taking code using them and converting it to code with manual
memory management seems like it would be a fairly major pain.
Especially if a person wanted to get it right...)

But thanks, theoretically.



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: A critic of Guido's blog on Python's lambda

2006-05-08 Thread David C.Ullrich
On Sun, 07 May 2006 10:36:00 -0400, Ken Tilton <[EMAIL PROTECTED]>
wrote:

>[...]
>
>Your spreadsheet does not have slots ruled by functions, it has one slot 
>for a dictionary where you store names and values/formulas.
>
>Go back to your example and arrange it so a and b are actual slots (data 
>members? fields?) of the spreadsheet class. You can just stuff numbers in a:
>
>sheet1.a = 42
>
>but b should be somehow associated with a rule when sheet1 is created. 
>As I said in the other post, also associate an on-change callback with 
>slots a and b.

I must be missing something - seems this should be easy using
__setattr__ and __getattr__. Then _literally_ there's just a
dict containing names and functions, but when you _use_ the
class it looks just like the above:

>[...]
>
>When that is done we can look at a working example and see how well 
>Python fared without macros and full-blown lambda.

No lambda in the non-programmer-half-hour implementation below.
You need to define a named function for each cell to use as
a callback. Except for that what are Cells supposed to do that
the implementation below doesn't do?

"""PyCells.py"""

class Cell:

  def __init__(self, name, owner, callback):
self.name = name
self.callback = callback
self.owner = owner

  def onchange(self, value):
self.value = value
self.callback(self, value)

class Cells:

  def __init__(self):
#self.slots = {}
#Oops, don't work so well with __setattr__:
self.__dict__['slots'] = {}

  def __setattr__(self, name, value):
self.slots[name].onchange(value)

  def __getattr__(self, name):
return self.slots[name].value

  def AddCell(self, name, callback):
self.slots[name] = Cell(name, self, callback)

***

Sample use:

cells = Cells()

def acall(cell, value):
  cell.owner.slots['b'].value = value + 1

cells.AddCell('a',acall)

def bcall(cell, value):
  cell.owner.slots['a'].value = value - 1

cells.AddCell('b',bcall)

cells.a = 42
print cells.a, cells.b
cells.b = 24
print cells.a, cells.b



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: A critic of Guido's blog on Python's lambda

2006-05-08 Thread David C.Ullrich
On Mon, 08 May 2006 08:05:38 -0500, David C. Ullrich
<[EMAIL PROTECTED]> wrote:

>[...]
>
>def acall(cell, value):
>  cell.owner.slots['b'].value = value + 1

Needing to say that sort of thing every time
you define a callback isn't very nice.
New and improved version:

"""PyCells.py"""

class Cell:

  def __init__(self, name, owner, callback):
self.name = name
self.callback = callback
self.owner = owner

  def onchange(self, value):
self.value = value
self.callback(self, value)

  def __setitem__(self, name, value):
self.owner.slots[name].value = value

class Cells:

  def __init__(self):
self.__dict__['slots'] = {}

  def __setattr__(self, name, value):
self.slots[name].onchange(value)

  def __getattr__(self, name):
return self.slots[name].value

  def AddCell(self, name, callback):
self.slots[name] = Cell(name, self, callback)

Sample:

cells = Cells()

def acall(cell, value):
  cell['b'] = value + 1

cells.AddCell('a',acall)

def bcall(cell, value):
  cell['a'] = value - 1

cells.AddCell('b',bcall)

cells.a = 42
print cells.a, cells.b
cells.b = 24
print cells.a, cells.b


#OR you could give Cell a __setattr__ so the above
#would be cell.a = value - 1. I think I like this
#version better; in applications I have in mind I
#might be iterating over lists of cell names.



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: A critic of Guido's blog on Python's lambda

2006-05-08 Thread David C.Ullrich
On 08 May 2006 12:53:09 -0700, [EMAIL PROTECTED] (Thomas
F. Burdick) wrote:

>Ken Tilton <[EMAIL PROTECTED]> writes:
>
>> No, you do not want on-change handlers propagating data to other
>> slots, though that is a sound albeit primitive way of improving
>> self-consistency of data in big apps. The productivity win with
>> VisiCalc was that one simply writes rules that use other cells, and
>> the system keeps track of what to update as any cell changes for
>> you. You have that exactly backwards: every slot has to know what
>> other slots to update. Ick.
>
>No no, that's fine and the way it should be: when you change a slot,
>it should know who to update.  And that's also the way it works in
>Cells.  The trick is that Cells takes care of that part for you:

I'm glad you said that - this may be what he meant, but it seems
more plausible than what he actually said.

> all
>the *programmer* has to care about is what values a slot depends on --
>Cells takes care of inverting that for you, which is important because
>that's a job that a computer is much better at than a human.

Fine. I suppose that is better; if b is going to return a + 1
the fact that this is what b returns should belong to b, not
to a. So a has an update list including b, so when a's value
is set a tells b it needs to update itself.

If we're allowed to pass (at some point, to some constructor
or other) something like (b, a + 1, [a]), which sets up a
cell b that shall return a + 1, and where the [a] is used
in the constructor to tell a to add b to a's update list
then this seems like no big deal.

And doing that doesn't seem so bad - now when the programmer
is writing b he has to decide that it should return a + 1
and also explicitly state that b shall depend on a; this
is all nice and localized, it's still _b_ telling _a_ to
add b to a's update list, and the programmer only has
to figure out what _b_ depends on when he's writing _b_.
Doesn't seem so bad. 

But of course it would be better to be able to pass just 
something morally equivalent to (b, a + 1) to whatever 
constructor and have the system figure out automatically 
that since b returns a + 1 it has to add a to b's update 
list. There must be some simple trick to accomplish that 
(using Python, without parsing code). (I begin to see the 
point to the comment about how the callbacks should fire 
when things are constucted.) Exactly what the trick is I 
don't see immediately.

In Cells do we just pass a rule using other cells to
determine this cell's value, or do we also include
an explicit list of cells that this cell depends on?



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: A critic of Guido's blog on Python's lambda

2006-05-09 Thread David C.Ullrich
On Mon, 08 May 2006 18:46:57 -0400, Ken Tilton <[EMAIL PROTECTED]>
wrote:

>
>
>David C. Ullrich wrote:
>> On 08 May 2006 12:53:09 -0700, [EMAIL PROTECTED] (Thomas
>> F. Burdick) wrote:
>> 
>> 
>>>Ken Tilton <[EMAIL PROTECTED]> writes:
>>>
>>>
No, you do not want on-change handlers propagating data to other
slots, though that is a sound albeit primitive way of improving
self-consistency of data in big apps. The productivity win with
VisiCalc was that one simply writes rules that use other cells, and
the system keeps track of what to update as any cell changes for
you. You have that exactly backwards: every slot has to know what
other slots to update. Ick.
>>>
>>>No no, that's fine and the way it should be: when you change a slot,
>>>it should know who to update.  And that's also the way it works in
>>>Cells.  The trick is that Cells takes care of that part for you:
>> 
>> 
>> I'm glad you said that - this may be what he meant, but it seems
>> more plausible than what he actually said.
>
>There may be some confusion here because there are two places for code 
>being discussed at the same time, and two sense of propagation.
>
>the two places for code are (1) the rule attached to A which is 
>responsible for computing a value for A and (2) a callback for A to be 
>invoked whenever A changes. Why the difference?
>
>In Cells, A is a slot such as 'background-color'. Whenever that changes, 
>we have to do something more. On Mac OS9 it was "InvalidateRect" of the 
>widget. In Cells-Tk, it is:
> (Tcl_interp "mywidget configure -background ")
>
>In my OpenGL GUI, it is to rebuild the display-list for the widget.
>
>That is the same no matter what rule some instance has for the slot 
>background-color, and different instances will have different rules.
>
>As for propagating, yes, Cells propagates automatically. More below on 
>that. What I saw in the example offered was a hardcoded on-change 
>callback that was doing /user/ propagation form B to A (and B to A! ... 
>doesn't that loop, btw? 

No, there's no looping in the example. Yes, the code determining what
b returns should be attached to b instead of to a, but the code I
gave does work as advertised. (I mean give me a break - I provided
a sample use so you could simply run it. Installing Python is not
hard.)

If you, um, look at the code you see that "cells.a = 42" triggers
cells.__setattr__, which fires a's callback; the callback then
reaches inside and sets the value of b _without_ going through
__setattr__, hence without triggering b's callback.

In Cells you can't have A depend on B and also B depend on A?
That seems like an unfortunate restriction - I'd want to be
able to have Celsius and Farenheit, so that setting either
one sets the other.

Of course if there are no loops it's easier to see how
you managed to do the stuff you were talking about elsewhere,
(at least sometimes) delaying execution until needed.

>Anyway...)
>
>> 
>> 
>>>all
>>>the *programmer* has to care about is what values a slot depends on --
>>>Cells takes care of inverting that for you, which is important because
>>>that's a job that a computer is much better at than a human.
>> 
>> 
>> Fine. I suppose that is better; if b is going to return a + 1
>> the fact that this is what b returns should belong to b, not
>> to a. So a has an update list including b, so when a's value
>> is set a tells b it needs to update itself.
>> 
>> If we're allowed to pass (at some point, to some constructor
>> or other) something like (b, a + 1, [a]), which sets up a
>> cell b that shall return a + 1, and where the [a] is used
>> in the constructor to tell a to add b to a's update list
>> then this seems like no big deal.
>> 
>> And doing that doesn't seem so bad - now when the programmer
>> is writing b he has to decide that it should return a + 1
>> and also explicitly state that b shall depend on a; this
>> is all nice and localized, it's still _b_ telling _a_ to
>> add b to a's update list, and the programmer only has
>> to figure out what _b_ depends on when he's writing _b_.
>> Doesn't seem so bad. 
>> 
>> But of course it would be better to be able to pass just 
>> something morally equivalent to (b, a + 1) to whatever 
>> constructor and have the system figure out automatically 
>> that since b returns a + 1 it has to add a to b's update 
>> list. There must be some simple trick to accomplish that 
>> (using Python, without parsing code).
>
>Right, you do not want to parse code. It really would not work as 
>powerfully as Cells, which notice any dynamic access to another cell 
>while a rule is running. So my rule can call a function on "self" (the 
>instance that wons the slot being calculated, and since self can have 
>pointers to other instances, the algorithm can navigate high and low 
>calling other functions before finally reading another ruled slot. You 
>want to track those.
>
>> Exactly what the trick is I 
>> don't see immediately.
>
>To compute a value for a 

Re: A critic of Guido's blog on Python's lambda

2006-05-10 Thread David C.Ullrich
On Tue, 09 May 2006 05:35:47 -0500, David C. Ullrich
<[EMAIL PROTECTED]> wrote:

>On Mon, 08 May 2006 18:46:57 -0400, Ken Tilton <[EMAIL PROTECTED]>
>wrote:
>[...]
>
>If you, um, look at the code you see that "cells.a = 42" triggers
>cells.__setattr__, which fires a's callback; the callback then
>reaches inside and sets the value of b _without_ going through
>__setattr__, hence without triggering b's callback.
>
>In Cells you can't have A depend on B and also B depend on A?
>That seems like an unfortunate restriction - I'd want to be
>able to have Celsius and Farenheit, so that setting either
>one sets the other.

Realized later that I hadn't thought this through.

I'd been assuming that of course we should be allowed to
have A and B depend on each other. Hence if a change in
A propagates to a change in B that change in B has to
be a non-propagating change - thought I was just so
clever seeing a way to do that.

But duh, if that's how things are then we can't have 
transitive dependencies working out right; surely we
want to be able to have B depend on A and then C
depend on B...

(And also if A and B are allowed to depend on each
other then the programmer has to ensure that the
two rules are inverses of each other, which seems
like a bad constraint in general, something non-trivial
that the programmer has to get right.)

So fine, no loops. If anything, if we know that
there are no loops in the dependencies that simplifies
the rest of the programming, no need for the sort of
finagling described in the first paragraph above.
But this raises a question:

Q: How do we ensure there are no loops in the dependencies?

Do we actually run the whole graph through some algorithm
to verify there are no loops?

The simplest solution seems like adding the cells one
at a time, and only allowing a cell to depend on 
previously added cells. It's clear that that would
prevent loops, but it's not clear to me whether or
not that disallows some non-looping graphs. A
math question the answer to which is not immediately
clear to me (possibly trivial, the question just
ocurred to me this second):

Say G is a (finite) directed graph with no loops. Is it always
possible to order the vertices in such a way that
every edge goes from a vertex to a _previous_ vertex?

>Of course if there are no loops it's easier to see how
>you managed to do the stuff you were talking about elsewhere,
>(at least sometimes) delaying execution until needed.
>
>>Anyway...)
>>
>>> 
>>> 
all
the *programmer* has to care about is what values a slot depends on --
Cells takes care of inverting that for you, which is important because
that's a job that a computer is much better at than a human.
>>> 
>>> 
>>> Fine. I suppose that is better; if b is going to return a + 1
>>> the fact that this is what b returns should belong to b, not
>>> to a. So a has an update list including b, so when a's value
>>> is set a tells b it needs to update itself.
>>> 
>>> If we're allowed to pass (at some point, to some constructor
>>> or other) something like (b, a + 1, [a]), which sets up a
>>> cell b that shall return a + 1, and where the [a] is used
>>> in the constructor to tell a to add b to a's update list
>>> then this seems like no big deal.
>>> 
>>> And doing that doesn't seem so bad - now when the programmer
>>> is writing b he has to decide that it should return a + 1
>>> and also explicitly state that b shall depend on a; this
>>> is all nice and localized, it's still _b_ telling _a_ to
>>> add b to a's update list, and the programmer only has
>>> to figure out what _b_ depends on when he's writing _b_.
>>> Doesn't seem so bad. 
>>> 
>>> But of course it would be better to be able to pass just 
>>> something morally equivalent to (b, a + 1) to whatever 
>>> constructor and have the system figure out automatically 
>>> that since b returns a + 1 it has to add a to b's update 
>>> list. There must be some simple trick to accomplish that 
>>> (using Python, without parsing code).
>>
>>Right, you do not want to parse code. It really would not work as 
>>powerfully as Cells, which notice any dynamic access to another cell 
>>while a rule is running. So my rule can call a function on "self" (the 
>>instance that wons the slot being calculated, and since self can have 
>>pointers to other instances, the algorithm can navigate high and low 
>>calling other functions before finally reading another ruled slot. You 
>>want to track those.
>>
>>> Exactly what the trick is I 
>>> don't see immediately.
>>
>>To compute a value for a slot that happens to have a rule associated 
>>with it, have a little cell datastructure that implements all this and 
>>associate the cell with the slot and store a pointer to the rule in the 
>>cell. Then have a global variable called *dependent* and locally:
>>
>> currentdependent = *dependent*
>> oldvalue = cell.value
>> newvalue = call cell.rule, passing it the self instance
>> *dependent* = currentvalue
>>
>> i

Re: Multiple Version Install?

2006-05-24 Thread David C.Ullrich
On Fri, 05 May 2006 07:44:45 -0500, David C. Ullrich
<[EMAIL PROTECTED]> wrote:
[...]
>Just curious: How does pythonxx.dll determine things
>like where to find the standard library? That's the
>sort of thing I'd feared might cause confusion...

Ok, it was a stupid question, cuz right there in the
registry it says

Python/PythonCore/1.5/PYTHONPATH = whatever.

All I can say is the last few times I wondered about this
question I did search the registry for PYTHONPATH and
didn't find it. Maybe I spelled it wrong or somthing.






David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: dynamic type changing

2006-05-28 Thread David C.Ullrich
On 28 May 2006 01:07:16 -0700, [EMAIL PROTECTED] wrote:

>>> I'm working on a "TempFile" class that stores the data in memory until
>>> it gets larger than a specified threshold (as per PEP 42).  Whilst
>>> trying to implement it, I've come across some strange behaviour.  Can
>>> anyone explain this?
>
>>> The test case at the bottom starts a TempFile at size 50 and prints its
>>> type.  It then increases the size to the threshold at which point
>>> "self" is changed to being a TemporaryFile.
>
>> Changed how ?-)
>
>Just by being assigned with a TemporaryFile object.  I thought that if
>you do
>
>instance = TempFile()
>
>that "instance" and "self" defined in the Class were the same thing so
>that if you changed the class of self, the class of instance would also
>change.
>
>Thanks very much for your example.  It has solved my problem and helped
>me understand a new pattern at the same time.

Bruno says you _can_ assign to __class__ but calls that "risky".
If you ever do feel the urge to assign a new value to some
object's __class__ it might be a good idea to first make certain
you can predict the behavior of the following:

class A:
  msg = 'A'
  def hmm(self):
print self.msg

class B:
  msg = 'B'
  def hmm(self):
print self.msg

x = A()
x.hmm()
x.__class__ = B
x.hmm()

class C:
  def __init__(self):
self.msg = 'C'
  def hmm(self):
print self.msg

class D:
  def __init__(self):
self.msg = 'D'
  def hmm(self):
print self.msg

x = C()
x.hmm()
x.__class__ = D
x.hmm()



David C. Ullrich
-- 
http://mail.python.org/mailman/listinfo/python-list