Re: shuffling elements of a list
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
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
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
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(???)
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(???)
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(???)
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(???)
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(???)
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?
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?
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?
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
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
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
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
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
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?
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
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