40 comments

[ 3.2 ms ] story [ 75.1 ms ] thread
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}
more like new feature rather than hidden feature. but agreed, it's very cool
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.
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)
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.
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.

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.
> 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)

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 :)

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)

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 '()'.

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.
Maybe with a one-bit half-adder?

     1
   + 1
   ----
     0
Two element finite field.
Indeed. There + becomes isomorphic to XOR and * to AND.
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
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.
>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.
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.
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]
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"

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.