Hacker News new | past | comments | ask | show | jobs | submit login
Hidden features of Python (stackoverflow.com)
148 points by carldz9 on July 13, 2010 | hide | past | favorite | 40 comments



My favorite feature (just released in Python 2.7, already in P3K) are dictionary comprehensions. E.g., you can now do:

    >>> {s: len(s) for s in ["one", "two", "three"]
    {"one": 3, "two": 3, "three": 5}


In python land (Django) for the past couple of months and I've been loving it, just thought this was a good excuse to fire up slime. In clojure...

    (defn map-comprehension [f sequence]
          (reduce #(assoc %1 %2 (f %2)) {} sequence))
usage:

    user> (map-comprehension count ["one" "two" "three"])
    {"three" 5, "two" 3, "one" 3}


Pre 2.7, you can just give the dict constructor a generator of tuples:

  >>> dict((s, len(s)) for s in ["one", "two", "three"])
  {'three': 5, 'two': 3, 'one': 3}


Thank you very much! Lack of simple dict-building had been bothering me.


map-comprehension is a bad name for that function, since it doesn't give you comprehension-like syntax, instead it is just a function that behaves like map but produces a map instead of another sequence. I'd call it map-map.


more like new feature rather than hidden feature. but agreed, it's very cool


There's a bunch of "hidden features of X" on stackoverflow (http://stackoverflow.com/search?q=%22hidden%20features%22...) if you liked this one


No one mentioned Python's strong typing hidden feature:

    (True + True) == 2

(sorry, one of my few pet-peeves after it bit me one time)


This is just a side-effect of bool being a subclass of int and True and False having the values 1 and 0, respectively. It might seem weird or surprising, but it's not a problem with Python's type system.

    >>> issubclass(bool, int)
    True
    >>> isinstance(True, int)
    True
    >>> int(True)
    1
    >>> int(False)
    0
    >>> True == 1
    True
    >>> False == 0
    True


Seems fine just so long as (False + False) doesn't equal True.


When is it ever desirable? I'm open to it having a use, but I don't see one. The only thing I've gotten from it is mismatched types that made it past some unit tests but blew up in the real world.


It's useful because it allows you to add together booleans to get a count of how many are true.

You can check if two out of three are true with

(bool1 + bool2 + bool3) >= 2

You can do

count_negatives = sum(number < 0 for number in numbers)


I was making a glib joke, but to answer your question this is the tradeoff of using a not-so-strongly-typed language. Weakly-typed languages often save you some typing (if you'll forgive the pun) and implicitly convert in ways that can make it difficult to prevent those mistakes.

It's just like Duck Typing- you're trading the need to explicitly specify an interface for the potential dangers of letting your interpreter "know what you mean".

If this is frequently a problem, well... there are a lot of strongly-typed languages out there waiting for you to give them a try.


> I was making a glib joke, but to answer your question this is the tradeoff of using a not-so-strongly-typed language.

Not in this case. In this case it results from:

1. Python historically not having booleans and using 0 and 1 instead

2. As a result, `bool` inherits from `int` for compatibility reasons

    >>> issubclass(bool, int)
    True
with False mapping to 0 and True to 1 for compatibility purposes

    >>> int(False), int(True)
    (0, 1)
3. Add isn't overridden on bool

    >>> bool.__add__
    <slot wrapper '__add__' of 'int' objects>
therefore, when adding two booleans you're really adding two integers.

Most non-strongly-typed languages will not have the following behavior

    >>> "foo" + 3
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: cannot concatenate 'str' and 'int' objects


In fact, to expand on the latter part of my comment, "weak typing" is generally understood as implying implicit type coercions or conversions at runtime. PHP and Javascript famously convert between numbers and strings depending on a bunch of factors (and usually the wrong way leading to unreliable results).

In that sense, Python is a very strongly typed language: from the top of my head, the only example of implicit type conversion in Python is the promotion of `int` to `long`, which has been removed from 3.x (all integer types were unified). All other conversions have to be explicit as far as I remember. That makes Python more strongly (but less statically) typed than Java (see the very strange overloading of the `+` operator when any operand is a string, as well as autoboxing since 1.5) and C# (C# allows for implicit type conversions, including in userland, and the cast operator doubles up as an explicit type conversion operator which I find terrible)


Python is fairly strongly typed in general. (At least compared to Perl and the like. Examples like True + True notwithstanding.) It is just also very dynamic.


This is only tangentially related, but try looking up "Iverson brackets" and Knuth's "Two notes on notation". One argument there is that False - True = -1 makes sign(x) = [x > 0] - [x < 0], which is convenient. I don't know of a case where True + True = 2 helps, but maybe something involving dual sums would be relevant.


The Iverson Bracket would already exist in a python that didn't subclass bool from int; '[boolean_expression]' would be, in python notation: 'int(boolean_expression)'.

Sounds kinda like I'm making the same argument as Knuth in forcing '[]' over '()'.


I used it in Code Golf to select a string from a list based on the truth of some conditions.

So no, it does not have a use :)


In mathematics

  True + True == False
might be a common interpretation.


When? Because the + symbol is often used to represent boolean OR, so T + T == T.


Two element finite field.


Indeed. There + becomes isomorphic to XOR and * to AND.


Maybe with a one-bit half-adder?

     1
   + 1
   ----
     0


The greatest hidden feature of Python (for me) was its standard library. Its sheer size and completeness, I should add.

Yes, I have heard of "batteries included" and all, but after working with Python for a year I still felt that the size of its library has been "hidden" from general programming public.

I love Python.


You can add the number of Python implementation to your list of "hidden" features as well: IronPython, CPython, Jython, PyPy, unladen-swallow, Python3 - and all of them are of pretty high quality!


python -m SimpleHTTPServer 8080


Port is optional and defaults to 8000 too.


Chaining comparison operators in Ruby: http://judofyr.net/posts/chained-comparisons.html


I feel validated that the chaining comparison operators feature is #1 in terms of votes (303 vs #2 at 249 as I write this). Nobody else seems to think it worth mentioning, but chaining comparison operators is a feature I'm really fond of in Lisp/Scheme: http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node124.html


I wouldn't say Lisp has chaining of comparisons, only chaining of identical comparisons: a < b < c --> (< a b c), but a < b <= c --> (and (< a b) (<= b c))


Still, chaining identical comparisons is a feature I think is cool.


python -m smtpd -n -c DebuggingServer localhost:2525

Runs a local SMTP server on port 2525. Very useful for debugging.


>Wrap an iterable with enumerate and it will yield the item along with its index.

Now that's a feature I wish I knew about sooner. I've been using:

    for item in a:
	print a.index(item), item
which has always felt kludgy.


Yes, enumerate is useful for that. But even if you did not now about it you could have used count from itertools to get the same effect:

  import itertools
  for (index, item) in zip(itertools.count(0), "hallo"):
      print index, item
Itertools is worth checking out for other goodies, too.


Before enumerate, the standard idiom for this was:

    for i in range(len(a)):
        print i, a[i]


Seriously? You must enjoy your O(n^2).


The sets I'm working on tend not to tend toward infinity.


Yes. But the approach with index only works for actual sets. And if you have actual sets, you might as well use Python's built-in sets.


So by "hidden features" they mean "can be found in the first pages of any tutorial"

(Ok, I didn't know about re.DEBUG)

EDIT: I'm not claiming this link is worthless. But I'd call it "great features of python" or simply "features of python"




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: