6 ms·
Python Language Features and Tricks
- densh 13y agoPython's unpacking is a poor man's pattern matching. I'd really love to see them extend it to support user-defined patterns like Scala's extractors or F#'s active patterns.
- munin 13y agoI think unpacking is just unpacking, languages that have pattern matching allow you to do something identical: # let i = (1,2,3) ;; val i : int * int * int = (1, 2, 3) # let a,b,c = i;; val a : int = 1 val b : int = 2 val c : int = 3
- odonnellryan 13y agoUnpacking pretty much does one thing, and it makes that one thing easier and a lot more readable. Combine that with list comprehension (from what I understand C#'s LINQ is similar) and you end up with code that's highly maintainable/readable (as long as you name your variables appropriately, of course). I believe Python supports pattern matching other than Regex as well.
- mercurial 13y agoPython list comprehensions are not lazy, though. If you generate [for x in xrange(1, 10000)] you'll get 10000 elements in your list. My understanding is that LINQ list comprehensions are that. > I believe Python supports pattern matching other than Regex as well. That's pattern matching on strings. The kind of pattern matching being discussed here is pattern matching on data types (see [1]). 1: http://en.wikipedia.org/wiki/Pattern_matching http://en.wikipedia.org/wiki/Pattern_matching
- whyever 13y ago'Lazy lists' are called generators in Python. Just use (...) Instead of [...] in your example.
- mercurial 13y agoI'm aware of generator expressions, but the fact that list comprehensions are not lazy can trip people if they are used to other languages with this feature, since they are usually lazy.
- hnriot 13y agoI don't agree, people are more likely to come from python that to python from a language that has lazy list comprehensions. But regardless, using a language requires that you learn it and I doubt many people think list comp is lazy. Pythonic programming obeys explicit over implicit, which which if you want a lazy version you explicitly use a lazy version.
- mercurial 13y ago> Pythonic programming obeys explicit over implicit, which which if you want a lazy version you explicitly use a lazy version. What does this have to do with anything? If the construct was defined as lazy, then it would be just as explicit. There is nothing about generator expressions that says "here, here, this is lazy".
- zodiac 13y agoReading through http://en.wikipedia.org/wiki/List_comprehension http://en.wikipedia.org/wiki/List_comprehension, it seems that there are roughly equal numbers of languages where "list comprehension" produces strict list as languages where it produces lazy lists. I think it's a lack of naming convention - the word "list" on its own means "strict list" in some languages and "lazy list" in others.
- mercurial 13y ago
- NAFV_P 13y agoI know bugger all Python, but I know negative indexing.
- ColinWright 13y agoGood for you. Did you know everything else?
- NAFV_P 13y ago> Good for you. Did you know everything else? Obviously not, after all I did say "I know bugger all Python". I did know about slices.
- jkork 13y agopatterns / tricks = language deficiencies Wake me up when Python will support tail call elimination and will get rid of GIL. For now this language is no better than PHP.
- odonnellryan 13y agoFor TRE: http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html http://neopythonic.blogspot.com/2009/04/tail-recursion-elimi... For the GIL, there are alternative implementations of Python (Jython, IronPython, etc.)
- sillysaurus3 13y agoHm... Python only supports 1000 recursions? That seems unsafe. It seems like anyone who writes functional-style code will run the risk of a stack overflow.
- Hellios 13y agoYou can increase the recursion limit like this: import sys sys.setrecursionlimit(x) Kind of a "hackish" way to do things but you can do it if you need to.
- theseoafs 13y ago^Although I think the idea is that you shouldn't need to. Any recursive implementation can either be easily translated to work iteratively, or can be implemented in such a way that 1000 levels of recursion should be more than enough. For example, 1000 levels of recursion is more than enough to count all the nodes in a binary tree unless the tree is extremely poorly balanced or inordinately large.
- deckiedan 13y agoBelieve it or not, it's actually deliberate. And not that uncommon in other languages too. The only way you can realistially have 'unlimited' recursion is to use tail call optimisation, which is deliberaterly not implemented in python: http://neopythonic.blogspot.co.uk/2009/04/final-words-on-tail-calls.html http://neopythonic.blogspot.co.uk/2009/04/final-words-on-tai... Is Guido's take on it. Essentially, as I understand it, his take is that massive recursion is confusing, and 'unpythonic'. And with the whole 'explicit is better than implicit' thing, I guess there is a point. Some times recursion is the best/most obvious solution, and then it is a bit annoying to not have TCO, but you can usually work around it.
- robinh 13y agoI have two questions. 1. I'm unfamiliar with the term 'unpacking'. Is it any different from pattern matching in, say, Haskell (but perhaps not as feature-rich)? 2. Aren't slices pretty much a staple in Python? I didn't think using them was considered a 'trick'.
- pekk 13y agoTuple unpacking: t = (1, 2) a, b = t # a == 1 and b == 2 Using slices is normal with lists
- dkersten 13y agoUnpacking is a limited form of what is called destructuring in other languages like Clojure. I would say that, in terms of feature-richness: unpacking < destructuring < pattern matching.
- tel 13y agoI'd extend that one step further unpacking < destructuring < pattern matching < first-class patterns where first-class patterns are increasingly becoming available in some languages which offer pattern matching (in particular, Haskell will have them soon).
- dkersten 13y agoI did a little googling, but am finding it difficult to find good clear information - do you have any articles where I can read about first-class patterns?
- kriro 13y agoWhy are there so many negative comments? Maybe those posters are vastly underestimating how many people that just start out read HN. I think it's a pretty good post to read after something like "X in Y minutes - Python" to get a very quick grasp of what the language is like. I'm also not ashamed to say that despite having written quite a few LOC of Python I wasn't aware of named slices for some reason and I think they can clear up some chunks of code I have produced (make it more readable)
- Estragon 13y agoI've been using python since the 90s, and I learned a few things from this post.
- shiven 13y agoRight after this string of replies, I was expecting Guido van Rossum would be next, saying he created Python and even he learnt something new...
- k3oni 13y agoSame here, learned something new today.
- maxerickson 13y agoA common theme running through named tuples, itertools and collections is Raymond Hettinger. He has also put together lots of tutorials and talks.
- JeffJenkins 13y agoIt's important to remember that OrderedDict keeps insertion order, it isn't an implementation of a sorted dictionary.
- lqdc13 13y agozip to unzip a dict is a very slow approach to do it Instead of mi = dict(zip(m.values(), m.keys())) Do mi = {v: k for (k, v) in m.iteritems()}
- mildtrepidation 13y agoWhen did support for dictionary comprehensions make it into 2.x? I could've sworn it didn't used to work, but I just tried it in the shell and sure enough, it does in 2.7.3.
- maxerickson 13y ago2.7: http://legacy.python.org/dev/peps/pep-0274/ http://legacy.python.org/dev/peps/pep-0274/
- chingjun 13y agoWow I didn't know that! I was always doing something like this mi = dict((v,k) for k,v in m.iteritems())
- nerfhammer 13y agomore importantly it's wrong - the iteration order of .values() and .keys() is not guaranteed to be consistent
- davidwtbuxton 13y agoThe order of items in the dictionary isn't stable, but the order of .keys() is guaranteed to be the same as the order of .values() (as long as you don't modify the dict in between calling one then the other). http://docs.python.org/2/library/stdtypes.html#dict.items http://docs.python.org/2/library/stdtypes.html#dict.items
- analog31 13y agoComing from a long history of languages like BASIC and Pascal, I will bookmark this tutorial. It seems to open up a lot of interesting Python features that were, quite frankly, not always easy to understand when described in plain text, but now seem pretty simple when presented as examples. I'll also think about the "collection of simple examples" next time I want to document something.
- PhantomGremlin 13y agoI used to bookmark tutorials like this, but now ... I just bookmark the HN discussion. Not only does that retain a link to the tutorial, but it also retains a link to a discussion that usually adds value to the tutorial. I'm assuming that HN discussions remain available for many years. Anyone know for sure if that is/isn't true?
- analog31 13y agoI hope so.
- avenger123 13y agoInstapaper has become my bookmarking tool. I don't even really sort it out anymore. I know it should be there when I need it and mostly the actual article is saved.
- yeukhon 13y agoSlice has always been a painful adventure for me. I always forget that [1:3] is not all inclusive. It's actually just range from 1 to 2. I believe in 2.7 zip is still returning a list rather than an iterator (izip in Python 2, zip in Python 3+). Another unappreciated stdlib is definitely functools. mock is also another awesome stdlib. functools, collections and itertools are definitely useful to make things faster. Also check out the list of stdlib. http://docs.python.org/2/library/ http://docs.python.org/2/library/
- lisper 13y ago> I always forget that [1:3] is not all inclusive. It's actually just range from 1 to 2. Just remember that for positive indices, len(slice(n,m)) == m - n
- NoodleIncident 13y agoSlices make sense when you realize that [n:n] is always empty, and [:n] + [n:] is always the whole list. From these two identities, all else follows.
- RK 13y agoNice reference. 1.29 happened to be exactly what I was looking for: for subset in itertools.chain(*(itertools.combinations(a, n) for n in range(len(a) + 1))) I spent way too much time writing a function to come up with these combinations.
- rockymeza 13y agoYou can also do itertools.chain.from_iterable(itertools.combinations(a, n) for n in range(len(a) + 1))
- evincarofautumn 13y agoA good reference, to be sure, but man, do I resent the term “trick” in programming. It implies a deception, or something clever that you wouldn’t think to look for, like opening a wine bottle with a shoe. These aren’t tricks, they’re (largely) standard library features that you would simply expect to exist. But maybe I’m underestimating the NIH effect.
- mamcx 13y agoGreat list, I do several mini-tutorials of python at http://runnable.com/u/mamcx http://runnable.com/u/mamcx. I try to pick several tricks for each theme
- liyanage 13y agoI think this is great, I've been doing Python for a while and I knew many of the features but I also learned a few new ones. I don't understand how this one to flatten lists works: a = [[1, 2], [3, 4], [5, 6]] [x for l in a for x in l] Can somebody explain what the order of operations is here and what the variables refer to in the various stages of evaluation?
- gshubert17 13y agoThe expression is a list comprehension with 2 nested for statements. It is similar to this, which names its result: result = [] for l in a: for x in l: result.append(x)
- vram22 13y agoYes. And the order of the two for's in the list comprehension was deliberately kept the same as the order of the two for loops in your explicit code, on purpose, for ease of remembering how the former (i.e. list comp) works.
- liyanage 13y agoThat order is the part that confused me. I expected to read it right-to-left, instead it's left to right for the for statements, then the expression on the left at the end. I see now that the Python docs explain this very clearly...
- vram22 13y agoYes. Meant to say that but forgot - that the Python docs explain it. That's where I read it myself :)
- jamesdutc 13y agoSo that flattening can also be written as: x = [[1,2], [3,4], [5,6]] [x for x in x for x in x] More perversely, we can also flatten with my invention: list(None for x in x if (yield from x) and False) # Python >=3.3 More reasonably, of course, list(itertools.chain.from_iterable(x))
- overgard 13y agoThis is awesome, I've been programming python for about 8 years now and a lot of these still surprised me.
- alien3d 13y agoSame as php.keep upgrading.
- sebastianavina 13y agoit's amazing how much work and effort almost any of this examples would take to implement in C
- maxerickson 13y agoThe fair comparison is probably to some data structure (list/array/whatever makes sense) and its rich companion library.
- edwinnathaniel 13y agoI've been using Python and Ruby on and off for a couple years (largely because I haven't found the need to use it seriously day job or side projects). One thing that strikes odd for me is how people describe Python/Ruby are way more readable than Java. I felt that Python, while more readable than Ruby (because Python uses less symbols), still contain more nifty tricks compare to Java. It's true that the resulting code is less code but behind that less line of code bugs might linger around because there might be plenty "intents" being hidden deep in the implementation of Python. The Python way that is touted many times is "explicit is better than implicit" seems to correlate better with the much maligned "Java is too verbose". Anyhow, the other day I was refreshing my Python skill and learned the default implicit methods that I can override ( those eq, gte, gt, lte, lt) and I wonder how overriding those resulted in less lines of code compare to Java overriding equals, hashCode, and implementing one Comparator method than can return -1, 0, 1 to cover the whole spectrum of gte, gt, lte, (and even equality, given the context). I suppose everything is relative...
- maxerickson 13y agoThe comparison functions are there to address the comparison for equality of things that don't have an order. So in some sense, they are more explicit (a minute with the docs explains that implementations only need to directly define 2 of them). -1,0,1 style comparisons still exist in Python 2.7, they were dropped in 3.0. Probably one of those things that could have gone either way. I think comparisons about readability aren't very useful (they are subjective, 'enough' counts), but I sure like the relative terseness of Python (to the point that I lament people who come over and write Java in Python (I don't mean to direct that at you, it's just a thing that happens, where people don't take advantage of things that are very idiomatic and thus clear even when terse)).
- edwinnathaniel 13y agoFair point and I learned early on during my college years not to import habit from one language to the other one. Mainly because "idiomatic" tend to depend on the internal implementation of the language.
- 13y ago