From: Michael Hudson Date: Thu Dec 4, 2003 14:52:19 Europe/London To: Bill Soudan Subject: Re: PEP 310/object lifetimes? Took a while to get back to this... On Wednesday, Nov 26, 2003, at 18:20 Europe/London, Bill Soudan wrote: > On Wed, 26 Nov 2003, Michael Hudson wrote: > >> :-) What happened to libicq? > > Died out from lack of use, I expect. Wasn't exactly the most > wonderful code to begin with anyway, and I didn't have the time to > make it so. Plus I think AOL dropped support for the ICQ protocol > version libicq implemented. More or less what I guessed. Which ICQ client do you use now? I've settled on centericq for the time being. >> Bear in mind that one of the use cases is: >> >> with lock: >> # have the lock here >> # released here >> >> *that* doesn't fit the __init__/__del__ pattern. Yeah, you could do >> >> class Locker: >> def __init__(self, lock): >> self.lock = lock >> self.lock.acquire() >> def __del__(self): >> self.lock.release() >> >> but that seems false. > > Why false? Well, false is perhaps the wrong way of putting it... contrived, maybe. > It's a great fit for me: the lock is held while the object exists. > No question about it, no room for programmer error in the presence > of exceptions. In addition, your Locker class is conceptually > simpler than a lock, as it has only one state: locked. > > I've used scoped locks exclusively for quite some time. I find that > most of the rare cases in which I need .acquire() and .release() are > workarounds for poor design. > >>> And since I've always been of the opinion Python's a little crazy >>> already with the large number of __special__ methods, re-using >>> existing is a plus. >> >> Well, here I have a 180 degree difference to you: I *abhor* the use of >> the same notation for more than one task. > > That's surprising to me, wouldn't the language grow out of control > if every high-level use case was supported with different notation? Heh, perhaps that was too strong. > For > instance, consider: > > x = "string" > print x[0:3] > > y = [1, 2, 3, 4, 5] > print y[0:3] > > or > > method = SomeObject.method > method(fred) > > method2 = someMethod > method2(fred) Of course, the argument here is that these are in fact the same thing :-) I guess you could say that part of the art of programming language design is deciding which notions to conflate in this way and which not. You can make a case for the conflation of holding resources and lifetimes of objects, but I'm not sure I buy it. >>> Finally, the concept is well known by C++ programmers, I use it >>> all the time. It'd be nice if Python supported the same, >>> especially for cases like me where you're working with C++ >>> bindings and you _need_ the underlying C++ object to go away. >> >> Why do you "_need_ the underlying C++ object to go away"? > > In my specific case, poorly written C++ code I can't change that > does things in its destructor. Oh, *ick*. For this case couldn't you implement an extension type that did roughly delete self->cpp_object; in an __exit__ method? That way you'd find out about it if the C++ code was poorly written enough to raise exceptions... > Even if Python guarantees an object will go away after all reference > to it have vanished (which I don't think it does anyway? I believe > that's the way the current implementation _works_, however), Nod. > there's still the issue of programmer error. I'd be nice have an > explicit way to say 'this object will no longer exist here'. I guess I have a lispers approach to this: view memory as infinite and assume the implementation does enough behind its back to maintain this illusion so long as not too many objects are actually live. >>> I wanted to discuss it with you since I see it as a >>> two-birds-one-stone type of thing. Actually, maybe more, another >>> use case I was thinking about: >>> >>> with o = ReallyExpensiveObject(): >>> # ... >>> >>> # no more ReallyExpensiveObject >> >> What if "# ..." is somelist.append(o)? > > Good question, something I've been considering. Here's my three > options: > > 1) don't let anyone refer to the with object, e.g. restrict it to > 'with SomeClass():'. Lots of problems with this one, notably, > reduces the utility and what's going to prevent SomeClass.__init__ > from spraying self pointers wherever it wants? > > 2) throw an exception at the end of the with block if the object > cannot be deleted. > > 3) don't delete the object. Allows the programmer to violate the > lifetime guarantee provided by (my proposed) with. Ew. > > My favorite is #2. Given that it's the only sane possibility, that's good :-) Even then, it's probably impossible in Jython, unless I'm missing something (and it would seem to permanently limit Python's GC choices). > You *shouldn't* be keeping references to the with object, so if you > do, throwing an exception seems like a reasonable thing to do. > >>> To me, this feature is very 'Python': simple, powerful, elegant. >> >> For all that you say you like Python, I think you might like it >> even more if you stopped trying to write C++ in it... > > I'd like to think it's more proper object oriented design than me > trying to write C++ in Python. And hey, let's face it, scoped locks > are one of the few *good* things in C++ :) I agree they work well there. OTOH, I'd feel bad encouraging people to write more __del__ methods given the irritating effects they can have (preventing collection of cycles being the main one). Cheers, mwh