
Python Language Features and Tricks - Bocker
http://sahandsaba.com/thirty-python-language-features-and-tricks-you-may-not-know.html
======
kriro
Why 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
I've been using python since the 90s, and I learned a few things from this
post.

~~~
shiven
Right after this string of replies, I was expecting Guido van Rossum would be
next, saying he _created_ Python and even he learnt something new...

------
densh
Python'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
I 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
Unpacking 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
Python 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
'Lazy lists' are called generators in Python. Just use (...) Instead of [...]
in your example.

~~~
mercurial
I'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.

~~~
zodiac
Reading 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
Fair enough, I retract my statement :) Maybe people are not surprised after
all.

------
edwinnathaniel
I'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...

~~~
barrkel
In isolated offline code, I think Ruby approaches the unreadable - but only
because DSLs are fashionable, and you have to understand the library involved
to understand the magic that's going on behind the scenes. With sufficient
online searching, you can understand things at a surface level, and with
enough time with a debugger you can appreciate all the mechanics that are
happening, but IMHO it still leaves you with an unpleasant taste in your mouth
at the sheer quantity of magic.

I do prefer Ruby to Python though. I much prefer monadic enumerators combined
with lambdas to list comprehensions, even though these tend to be eager in
Ruby but have the option of being lazy in Python. Itertools helps, but is
deeply hampered by Python's overly verbose lambda syntax.

~~~
msie
Been thinking about Python vs Ruby lately. I dread reading other people's Ruby
code (eg. if there is a problem in a library I'm using) but I don't have that
same dread reading Python code. Now if Python had blocks and RubyGems then I
would never give Ruby a second look.

~~~
e12e
What does RubyGems provide that isn't covered by pypy/eggs? I thought ruby and
python packaging was approximated feature parity here (which is to say, both
leave something to be desired, but work quite well).

------
JeffJenkins
It's important to remember that OrderedDict keeps _insertion_ order, it isn't
an implementation of a sorted dictionary.

------
lqdc13
zip 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
When 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
2.7:

[http://legacy.python.org/dev/peps/pep-0274/](http://legacy.python.org/dev/peps/pep-0274/)

------
robinh
I 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'.

~~~
dkersten
Unpacking 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
I'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
I 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?

~~~
Tyr42
[https://ghc.haskell.org/trac/ghc/wiki/ViewPatterns](https://ghc.haskell.org/trac/ghc/wiki/ViewPatterns)

That's the haskell extension.

To see a very nice use of them, check out this paper (pdf)
[http://strictlypositive.org/CJ.pdf](http://strictlypositive.org/CJ.pdf)

~~~
anaphor
How do view patterns make patterns "first-class"? To me that means able to
manipulate them as values, I don't see how view patterns allow that, they're
just syntactic sugar for case expressions.

~~~
tel
[http://www.reddit.com/r/haskell/comments/1vpaey/pattern_syno...](http://www.reddit.com/r/haskell/comments/1vpaey/pattern_synonyms_merged_into_ghchead/)

I spoke too eagerly—the new feature is just named and namespaced patterns.
It's a bit of a bump in power, but it's not fully general yet.

For true(-ish) first-class patterns take a look at Prisms in the lens package
or some of the other first-class pattern libraries.

------
analog31
Coming 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
I 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?

~~~
avenger123
Instapaper 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.

------
RK
Nice 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
You can also do

    
    
        itertools.chain.from_iterable(itertools.combinations(a, n) for n in range(len(a) + 1))

------
yeukhon
Slice 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
> 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

------
mamcx
Great 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
I 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
The 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
Yes. 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
That 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
Yes. Meant to say that but forgot - that the Python docs explain it. That's
where I read it myself :)

------
evincarofautumn
A 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.

------
sebastianavina
it's amazing how much work and effort almost any of this examples would take
to implement in C

~~~
maxerickson
The fair comparison is probably to some data structure (list/array/whatever
makes sense) and its rich companion library.

------
overgard
This is awesome, I've been programming python for about 8 years now and a lot
of these still surprised me.

~~~
alien3d
Same as php.keep upgrading.

------
NAFV_P
I know bugger all Python, but I know negative indexing.

~~~
ColinWright
Good for you. Did you know everything else?

~~~
NAFV_P
> _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
patterns / 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.

~~~
ColinWright
I suggest you are suffering from the Blub Paradox[0][1][2].

[0] [http://paulgraham.com/avg.html](http://paulgraham.com/avg.html)

[1] [http://c2.com/cgi/wiki?BlubParadox](http://c2.com/cgi/wiki?BlubParadox)

[2] [http://weblog.raganwald.com/2006/10/are-we-blub-
programmers....](http://weblog.raganwald.com/2006/10/are-we-blub-
programmers.html)

~~~
NAFV_P
> _I suggest you are suffering from the Blub Paradox[0][1][2]._

Writing some C will cure that disease, but the treatment has possible side
effects, like carpal tunnel syndrome.

