[Python-Dev] PEP 342 - Enhanced Iterators
There's a thread on c.l.py at the moment ("Controlling a generator the pythonic way") which is basically coming up with PEP 342. I've pointed them to PEP 342, but it's made me think that the name of the PEP could better indicate what it does. I propose "Coroutines via Enhanced Iterators". Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 343 rewrite complete
Phillip J. Eby wrote: > That's not a bug, it's a feature. If the object doesn't have a > 'close()' > method, clearly it doesn't need to be closed. If it's the "wrong" > object > for what you're using it for in the body of the 'with' block, it'll > show up > there, so this doesn't hide any errors. For those semantics, I think one of the following would be better: with local(obj): with scoped(obj): but those semantics apply better to __enter__ and __exit__ anyway. I think a "closing adaptor" should only work with objects that have a close() method. Perhaps: with scoped_closable(obj): Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Example for PEP 343
Bob Ippolito wrote: >> One more thought: Rather than just saving the precision, it is >> likely wiser, safer, and more general to just save and restore the >> whole context and let the wrapped block only work with a copy. >> >> oldcontext = decimal.getcontext() >> newcontext = oldcontext.copy() >> newcontext.prec += 2 >> yield None >> decimal.setcontext(oldcontext) >> >> This approach defends against various kinds of unruly behavior by the >> yield target. > > I think you're missing a decimal.setcontext(newcontext) before the > yield.. Seems to me this should be in the standard library ;) Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 343 - Abstract Block Redux
Steven Bethard wrote: > If I've misunderstood, and there are other situations when > "needs_finish" is required, it'd be nice to see some more examples. The other cases are where you want to do something in response to an exception, but not otherwise:: def gen(): try: yield except: print 'Got exception:', sys.exc_info() raise Personally, I think they're rare enough that you could use a decorator in those cases, but still have:: def gen(): try: yield finally: pass automatically make the generator conform to the do/with protocol. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 343 - Abstract Block Redux
Shane Hathaway wrote: > PEP 340 is very nice, but it became less appealing to me when I saw > what it would do to "break" and "continue" statements. Absolutely. I really liked PEP 340, but two things stood out to me as being flawed: 1. Looping - it took a while for me to realise this was bugging me - the unintuitive behaviour of break and continue clarified it for me. 2. Not re-raising exceptions automatically. I actually proposed at one point that any exception should be re-raised at the end of the iterator finalisation unless another exception was raised (not StopIteration, etc). I still continue to support this. It also deals with the control-flow issue (being hidden). PEP 3XX has some other nice things. I have two opposing views on for-loops supporting finalisation of iterators though: 1. for-loops should support finalisation. However, in that case every iterator should be finalisable by default, and you should have to go out of your way to prevent it (or prevent forced exhaustion of the iterator). I think there's zero chance of this proposal being accepted ;) 2. for-loops should not support finalisation at all, and if you want finalisation semantics you need to enclose the for-loop in a do/with statement. I think the most important thing is that the semantics must be absolutely clear to someone looking at the code for the first time, without knowing the particulars of the statement being used. To me that suggests that the following 3 factors are the most important: 1. Non-looping semantics. Looping semantics require me to think more about the actual behaviour in the presence of break/continue. 2. An exception raised in the body of the statement must be propagated outside of the statement. I'm willing to accept another exception being raised in its place, but in that case I think it would be a good idea to chain the exceptions in some way. In any case, if the body of the statement terminates abnormally, it should not be possible for the statement to change that abnormal exit. 3. There should be a single statement (other than try...finally) that has finalisation semantics i.e. for-loop doesn't. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Chained Exceptions
James Y Knight wrote: > Of course you can already do similar with current python, it just > can't be spelled as nicely, and the default traceback printer won't > use the info: > > try: >raise AError > except: >newException = BError() >newException.cause=sys.exc_info() >raise newException Well, one thing you can do is (somewhat evil ;) :: import sys try: raise AError, 'message' except: exc_type, exc_value, exc_traceback - sys.exc_info() raise BError, exc_value, exc_traceback with the result: Traceback (most recent call last): File ... raise AError, 'message' BError: message So you store the original exception as the argument to the new exception (so it's accessible). This has the nice side effect that message is displayed in the traceback - but the type has changed. Whilst in the above example, it's particularly evil, in the case where the original exception came from a function call and you want to translate the type it works very nicely. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340: Deterministic Finalisation (new PEP draft, either a competitor or update to PEP 340)
Greg Ewing wrote: > Nick Coghlan wrote: >> Hmm, with that approach, a code inspection tool like pychecker could >> be used to pick up the slack, and flag generators which have a yield >> inside a try/finally or a user defined statement without applying >> the "needs finalisation" decorator > > What about giving them an __exit__ method if and only > if they have a yield inside a try/finally? Old generators > won't be doing that, because it's currently illegal. It's possible to create a generator that does not contain a finally, but still needs cleanup. def gen(): try: yield except: print 'cleanup' raise Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340 - For loop cleanup, and feature separation
Greg Ewing wrote: > I'm still bothered by the idea of for-loops not participating > in the new generator finalization protocol. I agree - that's always been nagging at me too. The problem with it is that then you either: 1. Have a guarantee that an iterator will be exhausted when the for loop exits (as per block statements); OR 2. Rely on garbage collection (reference counting, etc) to ensure finalisation. Personally, I'm of the opinion that we should make a significant break (no pun intended ;) and have for-loops attempt to ensure that iterators are exhausted. An iterator could be specifically designed to prevent that if needed, but in the vast majority of cases an iterator is never used after the for-loop. An example of an iterator that was specifically designed to continue working after its initial for-loop would be:: def gen(): try: setup1() try: yield 1 finally: cleanup1() except StopIteration: pass setup2() try: yield 2 finally: cleanup2() This allows cleanup, but then continued usage. > So I think that, in the interests of least surprise, > for-loops should provide the same finalization promises > as block statements. Agreed. > If that is done, it becomes easier to decide whether > the block statement should loop. The answer is probably > no: If you're writing a loop, you use a for-statement; > if you're not, you use a block-statement. This helps > to clearly differentiate the two, and provide > justification for having two statements. Agreed. > I'm also starting to like the idea of having a > completely separate protocol for block-statements +1 > and an adaptor of some kind for using generators to > implement them. My preference would be direct syntactic support... Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340: Breaking out.
Greg Ewing wrote: > Seems to me it should be up to the block iterator whether > a break statement gets caught or propagated, since it's > up to the block iterator whether the construct behaves > like a loop or not. > > This could be achieved by having a separate exception > for breaks, as originally proposed. > > If the iterator propagates the Break exception back out, > the block statement should break any enclosing loop. > If the iterator wants to behave like a loop, it can > catch the Break exception and raise StopIteration > instead. In this scenario (and I'm not saying I approve or disapprove) I think BreakIteration should inherit from StopIteration (thus retaining the existing PEP 340 semantics if uncaught):: Iteration | +- ContinueIteration | +- StopIteration | +- BreakIteration I think no matter what it would be useful to be able to separate a break from a stop sometimes, but there are many cases where they are the same thing. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340: Breaking out.
Aahz wrote: > My standard workaround is using exceptions, but I'm not sure how that > interacts with a block: > > try: > for name in filenames: > with opened(name) as f: > if f.read(2) == 0xFEB0: > raise Found > except Found: > pass For any sane block iterator, it will work as expected. However, an evil block iterator could suppress the `Found` exception. A sane block iterator should re-raise the original exception. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340 -- concept clarification
Nick Coghlan wrote: > Ah, someone else did post this idea first :) I knew I was standing on the shoulders of others :) > To deal with the generator issue, one option would be to follow up on > Phillip's idea of a decorator to convert a generator (or perhaps any > standard iterator) into a block iterator. > > I think this would also do wonders for emphasising the difference > between for loops and block statements. I think if we are going to emphasise the difference, a decorator does not go far enough. To use a decorator, this *must* be valid syntax:: def gen(): try: yield finally: print 'Done!' However, that generator cannot be properly used in a for-loop. So it's only realistically valid with the decorator, and used in a block statement (resource suite ;) My feeling is that the above should be a SyntaxError, as it currently is, and that a new keyword is needed which explicitly allows the above, and creates an object conforming to the resource protocal (as I called it). Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340 -- concept clarification
Delaney, Timothy C (Timothy) wrote: > Guido van Rossum wrote: > >> I'd like the block statement to be defined exclusively in terms of >> __exit__() though. > > 1. If an iterator declares __exit__, it cannot be used in a for-loop. >For-loops do not guarantee resource cleanup. > > 2. If an iterator does not declare __exit__, it cannot be used in a > block-statement. >Block-statements guarantee resource cleanup. Now some thoughts have solidified in my mind ... I'd like to define some terminology that may be useful. resource protocol: __next__ __exit__ Note: __iter__ is explicitly *not* required. resource: An object that conforms to the resource protocol. resource generator: A generator function that produces a resource. resource usage statement/suite: A suite that uses a resource. With this conceptual framework, I think the following makes sense: - Keyword 'resource' for defining a resource generator. - Keyword 'use' for using a resource. e.g. :: resource locker (lock): lock.acquire() try: yield finally: lock.release() use locker(lock): # do stuff Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340 -- concept clarification
Guido van Rossum wrote: > I'd like the block statement to be defined exclusively in terms of > __exit__() though. This does actually suggest something to me (note - just a thought - no real idea if it's got any merit). Are there any use cases proposed for the block-statement (excluding the for-loop) that do *not* involve resource cleanup (i.e. need an __exit__)? This could be the distinguishing feature between for-loops and block-statements: 1. If an iterator declares __exit__, it cannot be used in a for-loop. For-loops do not guarantee resource cleanup. 2. If an iterator does not declare __exit__, it cannot be used in a block-statement. Block-statements guarantee resource cleanup. This gives separation of API (and thus purpose) whilst maintaining the simplicity of the concept. Unfortunately, generators then become a pain :( We would need additional syntax to declare that a generator was a block generator. OTOH, this may not be such a problem. Any generator that contains a finally: around a yield automatically gets an __exit__, and any that doesn't, doesn't. Although that feels *way* too magical to me (esp. in light of my example below, which *doesn't* use finally). I'd prefer a separate keyword for block generators. In that case, having finally: around a yield would be a syntax error in a "normal" generator. :: resource locking(lock): lock.acquire() try: yield finally: lock.release() block locking(myLock): # Code here executes with myLock held. The lock is # guaranteed to be released when the block is left (even # if via return or by an uncaught exception). To use a (modified) example from another email:: class TestCase: resource assertRaises (self, excClass): try: yield except excClass: return else: if hasattr(excClass, '__name__'): excName = excClass.__name__ else: excName = str(excClass) raise self.failureException, "%s is not raised" % excName block self.assertRaises(TypeError): raise TypeError Note that this *does* require cleanup, but without using a finally: clause - the except: and else: are the cleanup code. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340 -- loose ends
Another loose end (which can partially explain why I still thought __next__ took an exception ;) In "Specification: Generator Exit Handling":: "When __next__() is called with an argument that is not None, the yield-expression that it resumes will return the value attribute of the argument." I think this should read:: "When __next__() is called with an argument that is not None, the yield-expression that it resumes will return the argument." Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340 -- loose ends
Guido van Rossum wrote: > Oops. Read the most recent version of the PEP again. __next__() > doesn't take an exception argument, it only takes a value. Maybe this > removes your concern? Actually, I misinterpreted it, assuming that the value passed in was an exception instance because the previous versions worked that way. This has been going on too long ;) > Ah, here we see the other misconception (caused by not reading the > most recent version of the PEP). __exit__() shouldn't call __next__() > -- it should just raise the exception passed in unless it has > something special to do. Ah - I think this needs to be explained better. In particular, in the specification of the __next__ and __exit__ methods it should state what exceptions are expected to be raised under what circumstances - in particular, that __exit__ is expected to raise the passed in exception or StopIteration. This is only explained in the Generator Exception Handling specification, but it's applicable to all iterators. >> Finally, I think there is another loose end that hasn't been >> addressed:: >> >> When __next__() is called with an argument that is not None, the >> yield-expression that it resumes will return the value attribute >> of the argument. If it resumes a yield-statement, the value is >> ignored (or should this be considered an error?). When the >> *initial* call to __next__() receives an argument that is not >> None, the generator's execution is started normally; the >> argument's value attribute is ignored (or should this be >> considered an error?). When __next__() is called without an >> argument or with None as argument, and a yield-expression is >> resumed, the yield-expression returns None. > > Good catch. > >> My opinion is that each of these should be an error. > > Personally, I think not using the value passed into __next__() should > not be an error; that's about the same as not using the value returned > by a function you call. Now that I understand that the parameter to __next__ is not an exception, I agree. > I agree that calling the initial __next__() of a generator with a > non-None argument should be considered an error; this is likely caused > by some kind of logic error; it can never happen when the generator is > called by a block statement. Cheers. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340 -- loose ends
Guido van Rossum wrote: > [Delaney, Timothy] >> PEP 340 does not address "normal" iterators very well, but a >> properly-constructed iterator will behave correctly. > > This is by design. Yep - I agree. >> The PEP though is very generator-focussed. > > Disagree. The PEP describes most everything (e.g. the block statement > semantics) in terms of iterators, and then describes how the new APIs > behave for generators. Again, agree. What I meant is that there are no examples of how to actually implement the correct semantics for a normal iterator. Doing it right is non-trivial, especially with the __next__ and __exit__ interaction (see below). >> The issues I see for "normal" >> iterators (and that need to be addressed/stated in the PEP) are: >> >> 1. No automatic handling of parameters passed to __next__ and >>__exit__. In a generator, these will raise at the yield >>-statement or -expression. A "normal" iterator will have >>to take care of this manually. > > Not sure what you mean by this. If __next__() is defined, it is passed > the parameter; if only next() is defined, a parameter (except None) is > an error. That seems exactly right. Also, if __exit__() isn't defined, > the exception is raised, which is a very sensible default behavior > (and also what will happen to a generator that doesn't catch the > exception). What I meant is how the iterator is meant to handle the parameters passed to each method. PEP 340 deals with this by stating that exceptions will be raised at the next yield-statement or -expression. I think we need an example though of how this would translate to a "normal" iterator. Something along the lines of:: class iterator (object): def next (self): return self.__next__() def __next__(self, arg=None): value = None if isinstance(arg, ContinueIteration): value = arg.value elif arg is not None: raise arg if value is None: raise StopIteration return value def __exit__(self, type=None, value=None, traceback=None): if (type is None) and (value is None) and (traceback is None): type, value, traceback = sys.exc_info() if type is not None: try: raise type, value, traceback except type, exc: return self.__next__(exc) return self.__next__() >> As another option, it might be worthwhile creating a base iterator type >> with "correct" semantics. > Well, what would the "correct" semantics be? What would passing a > parameter to a list iterator's __next__() method mean? Sorry - I meant for user-defined iterators. And the correct semantics would be something like the example above I think. Except that I think most of it would need to be in a separate method (e.g. _next) for base classes to call - then things would change to be something like:: class iterator (object): ... def _next (self, arg): if isinstance(arg, ContinueIteration): return arg.value elif arg is not None: raise arg def __next__(self, arg=None): value = self._next(arg) if value is None: raise StopIteration return value ... Finally, I think there is another loose end that hasn't been addressed:: When __next__() is called with an argument that is not None, the yield-expression that it resumes will return the value attribute of the argument. If it resumes a yield-statement, the value is ignored (or should this be considered an error?). When the *initial* call to __next__() receives an argument that is not None, the generator's execution is started normally; the argument's value attribute is ignored (or should this be considered an error?). When __next__() is called without an argument or with None as argument, and a yield-expression is resumed, the yield-expression returns None. My opinion is that each of these should be an error. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 340 -- loose ends
Phillip J. Eby wrote: > Specifically, I propose that PEP 340 *not* allow the use of "normal" > iterators. Instead, the __next__ and __exit__ methods would be an > unrelated protocol. This would eliminate the need for a 'next()' > builtin, > and avoid any confusion between today's iterators and a template > function > for use with blocks. PEP 340 does not address "normal" iterators very well, but a properly-constructed iterator will behave correctly. The PEP though is very generator-focussed. The issues I see for "normal" iterators (and that need to be addressed/stated in the PEP) are: 1. No automatic handling of parameters passed to __next__ and __exit__. In a generator, these will raise at the yield-statement or -expression. A "normal" iterator will have to take care of this manually. This could be an argument to only allow generator-iterators to be used with PEP 340 semantics (i.e. continue , block), but I don't think it's a very compelling one. Although perhaps the initial implementation could be restricted to generator-iterators. So if a for-loop used `continue ` it would have a check (at the start of the for loop) that the iterator is a generator-iterator. Likewise, a block-statement would always include this check. As another option, it might be worthwhile creating a base iterator type with "correct" semantics. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] @decoration of classes
Nick Coghlan wrote: ># A decorator that does not alter its argument >def register(callable): > # Register the callable somewhere > ... > return callable > ># Decorated factory function >@register >def factory(): > pass > ># Post-decorated class >class factory: > pass >register(factory) > ># Metaclass >class RegisteredType(type): > def __init__(self, name, bases, dict): >super(self, RegisteredType).__init__(self, name, bases, dict) >register(self) > >class factory: > __metaclass__ = RegisteredType > ># Class decorator (not currently possible) >@register >class factory: > pass class factory: @register def __call__(self): pass Just as an additional data point - obviously not applicable in all cases. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
python-dev@python.org
Rodrigo Dias Arruda Senra wrote: > However, there are two other issues: > 1) If a *graphical* application dumps messages to the console, >that might be disruptive to other console applications. >IMVHO, a log file should be used instead. (strong argument) Perhaps instead webbrowser.py should redirect to a (preferably specified) log file. The detail is then still available, but hidden from normal usage. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] LinkedHashSet/LinkedHashMap equivalents
Steven Bethard wrote: > def filterdups(iterable): > seen = set() > for item in iterable: > if item not in seen: > seen.add(item) > yield item > > Adding this to, say, itertools would cover all my use cases. And as > long as you don't have too many duplicates, filterdups as above should > keep memory consumption down better. Thinking about this further - memory usage would be almost identical. By the time you completed the iterable, you would have built up exactly the same set internally - although probably not as memory efficient since it would be being built piecemeal. OTOH, an ordered set has a bit of extra memory for maintaining the order, so it's going to be pretty close. The only thing this gains you (and it's significant) is the ability to work on any iterable lazily. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] LinkedHashSet/LinkedHashMap equivalents
Jeff Bauer wrote: > I'm not specifically lobbying for its inclusion in > stdlib, but I often find an ordered dict useful when I > want both ordered and random access, e.g. situations: > >- database table fields/attributes >- drop down field selectors Yep - these are also cases that are familiar to me - it's the type of thing you don't think about until you actually need it. > In both cases, I could get by with other techniques, but I > would use stdlib ordered dicts if they were available. > I also prefer the term "ordered dict" to LinkedHashXXX. You may notice the subject is LinkedHashXXX *equivalents* ;) There is no way I would ever propose adding them with those names. OTOH, "ordered set" and "ordered dict" implies different things to different people - usually "sorted" rather than "the order things were put in". Perhaps "temporally-ordered" ;) BTW, just to clarify the semantics: Set: Items are iterated over in the order that they are added. Adding an item that compares equal to one that is already in the set does not replace the item already in the set, and does not change the iteration order. Removing an item, then re-adding it moves the item to the end of the iteration order. Dict: Keys are iterated over in the order that they are added. Setting a value using a key that compares equal to one already in the dict replaces the value, but not the key, and does not change the iteration order. Removing a key (and value) then re-adding it moves the key to the end of the iteration order. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] LinkedHashSet/LinkedHashMap equivalents
Greg Ward wrote: > I'll attach another approach to the same problem, an ordered > dictionary object. I believe the semantics of > adding/readding/deleting keys is the same as java.util.LinkedHashMap > -- certainly it seems the most sensible and easy-to-implement > semantics. That's essentially the same approach I used - I didn't get around to properly implementing a doubly-linked list between the keys - I just maintained a list with the correct order. If I'm going to write a Cookbook recipe though I should probably do it properly ... Personally, I think it would be quite nice if all python dictionaries had these semantics - it would be nice to be able to say that items will be returned in the order they're inserted - but I wouldn't want to incur the additional cost in such a fundamental data structure. One thing I did notice - dict.__repr__ and dict.__str__ don't produce strings in the iteration order of subclasses - they always use the arbitrary dict iteration order. Is this intentional? Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] LinkedHashSet/LinkedHashMap equivalents
The perennial "how do I remove duplicates from a list" topic came up on c.l.py and in the discussion I mentioned the java 1.5 LinkedHashSet and LinkedHashMap. I'd thought about proposing these before, but couldn't think of where to put them. It was pointed out that the obvious place would be the collections module. For those who don't know, LinkedHashSet and LinkedHashMap are simply hashed sets and maps that iterate in the order that the keys were added to the set/map. I almost invariably use them for the above scenario - removing duplicates without changing order. Does anyone else think it would be worthwhile adding these to collections, or should I just make a cookbook entry? Cheers. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] Getting rid of unbound methods: patch available
Guido van Rossum wrote: > [Timothy Delaney] >> If im_func were set to the class where the function was defined, I >> could definitely avoid the second part of the trawling (not sure >> about the first yet, since I need to get at the function object). > > Instead of waiting for unbound methods to change their functionality, > just create a metaclass that sticks the attribute you want on the > function objects. Yep - that's one approach I've considered. I've also thought about modifying the code objects, which would mean I could grab the base class directly. It's definitely not the most compelling use case in the world ;) Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] Getting rid of unbound methods: patch available
Guido van Rossum wrote: > Keeping im_class would be tricky -- the information isn't easily > available when the function is defined, and adding it would require > changing unrelated code that the patch so far didn't have to get near. > Also, it would not be compatible -- the unbound method sets im_class > to whichever class was used to retrieve the attribute, not the class > in which the function was defined. I actually do have a use case for im_class, but not in its current incarnation. It would be useful if im_class was set (permanently) to the class in which the function was defined. My use case is my autosuper recipe. Currently I have to trawl through the MRO, comparing code objects to find out which class I'm currently in. Most annoyingly, I have to trawl *beyond* where I first find the function, in case it's actually come from a base class (otherwise infinite recursion can result ;) If im_func were set to the class where the function was defined, I could definitely avoid the second part of the trawling (not sure about the first yet, since I need to get at the function object). Cheers. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] Re: super() harmful?
Guido van Rossum wrote: >> and the cumbersome way in which you have to invoke super. > > Given Python's dynamic nature I couldn't think of a way to make it > less cumbersome. I see you tried (see below) and couldn't either. At > this point I tend to say "put up or shut up." Well, there's my autosuper recipe you've seen before: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/286195 which does basically what Philip descibes ... >>> import autosuper >>> >>> class A (autosuper.autosuper): ... def test (self, a): ... print 'A.test: %s' % (a,) ... >>> class B (A): ... def test (self, a): ... print 'B.test: %s' % (a,) ... self.super(a + 1) ... >>> class C (A): ... def test (self, a): ... print 'C.test: %s' % (a,) ... self.super.test(a + 1) ... >>> class D (B, C): ... def test (self, a): ... print 'D.test: %s' % (a,) ... self.super(a + 1) ... >>> D().test(1) D.test: 1 B.test: 2 C.test: 3 A.test: 4 It uses sys._getframe() of course ... Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] Out-of-date FAQs
Aahz wrote: > Yes. Until last July, the company I work for was still using 1.5.2. > Our current version is 2.2. I think that the FAQ should be usable for > anyone with a "reasonably current" version of Python, say at least two > major versions. IOW, answers should continue to work with 2.2 during > the lifetime of 2.4. That seems reasonable to me. Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Out-of-date FAQs
While grabbing the link to the copyright restrictions FAQ (for someone on python-list) I noticed a few out-of-date FAQ entries - specifically, "most stable version" and "Why doesn't list.sort() return the sorted list?". Bug reports have been submitted (and acted on - Raymond, you work too fast ;) I think it's important that the FAQs be up-to-date with the latest idioms, etc, so as I have the time available I intend to review all the existing FAQs that I'm qualified for. As a general rule, when an idiom has changed, do we want to state both the 2.4 idiom as well as the 2.3 idiom? In the case of list.sort(), that would mean having both: for key in sorted(dict.iterkeys()): ...do whatever with dict[key]... and keys = dict.keys() keys.sort() for key in keys: ...do whatever with dict[key]... Tim Delaney ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] MinGW And The other Py2.4 issue
"Martin v. Löwis" wrote: > Not at all. I'm talking about the release process, and prerequisites > required in that process. This is worth mentioning because the list > of prerequisites you need to perform a Python release is already quite > long: Ah - sorry - misinterpreted. What is the size of the generated libpython24.a? Unfortunately, I don't happen to have binutils installed in my work cygwin (pulling it down now, but it's very slow ...) so I can't check myself (I've built the 2.3 one at home before ...). Tim Delaney ___ Python-Dev mailing list [EMAIL PROTECTED] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] MinGW And The other Py2.4 issue
"Martin v. Löwis" wrote: > Paul Moore wrote: >> Thanks for your comments. Your support for the viability of building >> extensions using mingw is important to me, so if you still have any >> concerns, let me know and I will do my best to address them. > > I understand that one still needs to build libpython24.a in order to > use this process. As I have said, I'd happily ship that file with the > 2.4.1 MSI, unless the release manager tells me that this would an > unacceptable new feature, and as long as somebody provides a fully > automatic build process integrated into msi.py; for that build > process, > it is ok to assume that a cygwin installation is in c:\cygwin. I think we should aim to support MSYS as well as Cygwin, but perhaps not for the first version where this goes in. OTOH, is it really necessary to have either MSYS or Cygwin? MinGW32 works standalone - distutils should be able to just invoke it. Tim Delaney ___ Python-Dev mailing list [EMAIL PROTECTED] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] Re: The Other Py2.4 issue?
Adam Bark wrote: > Now this might sound a bit stupid but I've only been programming in > python for about 6 months and before that about the same on VB. Anyway > here goes, as python is built in C & C++ surely every piece of python > code has a corresponding piece of C/C++ albeit more complex. So would > it be possible to somehow make a program to convert the Python to C & > C++ which can then be compiled with a C/C++ compiler. Yes. And it would run at about the same speed as CPython. The only way to significantly improve this is to remove much of the dynamism of Python. As an example, I've been playing around with Raymond's constant binding - making it do more aggressive binding (I'll give an example later). By binding constants, I'm able to reduce the runtimes for psyco-compiled versions of friendly code (lots of things that can be converted into constant references) from around 2 seconds to less than 0.001 seconds. That's a very significant speedup. Unfortunately, it doesn't translate as well into real-world code - or even benchmarks (parrotbench for example gets a slight speedup but it's not overly significant). As a quick example if the changes I'm playing with, def func() docutils.parsers.rst.states.struct.__init__ Raymond's generates: JUMP_FORWARD 0 LOAD_CONST(docutils) LOAD_ATTR (parsers) LOAD_ATTR (rst) LOAD_ATTR (states) LOAD_ATTR (struct) LOAD_ATTR (__init__) Mine generates 0 JUMP_ABSOLUTE 15 3 NOP 4 NOP 5 NOP 6 NOP 7 NOP 8 NOP 9 NOP 10 NOP 11 NOP 12 NOP 13 NOP 14 NOP 15 LOAD_CONST (http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] Re: 2.4 news reaches interesting places
Michael Hudson wrote: > Anthony's Australian, people expect this sort of thing from him :) As another Australian, I think that "Making Python Not Suck" implies that if you don't do extra things, Python Sucks. This is not a good thing IMO. "Making Python Suck Less" would be even worse. How about "Python - You Can Have Your Cake And Eat It Too". Tim Delaney ___ Python-Dev mailing list [EMAIL PROTECTED] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com