Live data from Hacker News

Python idioms I wish I'd learned earlier

prooffreaderplus.blogspot.com

151–160 of 174 posts

Re: Python idioms I wish I'd learned earlier

#151
post #61

Earlier quoted context omitted.

It's not just a tweak to the parser, and it does have to do with the type system, but you're right that it's not about static typing. The issue is that there are languages (like C) where typing is static but weak, so e.g. booleans are also integers and can have integer operations like '>' applied to them. In other words, the problem is that in C True == 1 and 1 > 2 is a valid expression. In Python, which has strong(e…

Yes, you really can just tweak the parser; just (a) don't have a rule allowing comparisons to appear as children of other comparisons, and (b) add a rule that permits chains of comparisons. Types have zilch to do with this. It's 100% a tweak to the parser.

You are absolutely correct that it could be implemented as 100% a tweak to the parser.

Assuming filmor is correct, in practice as it happens to be implemented in the Python code base it is not 100% a tweak to the parser - changing the structure of the produced AST means tweaks down the line. I think the change to the parser is still the most meaningful piece, though, even there.

Re: Python idioms I wish I'd learned earlier

#152
post #55

Earlier quoted context omitted.

I really like haskell's "++" for list concatenation. Makes a lot of sense.

Although the `++` is associated with increment from anyone coming to python from the C languages. Its tricky; if you want to do vectors, use numpy.

Haskell also uses for combining any monoid, but of course in Python that was once not-equal... Maybe a dot? It's string concatenation in Perl, and function composition in Haskell. Interestingly, both of those are monoids...

Re: Python idioms I wish I'd learned earlier

#153
post #18

Earlier quoted context omitted.

But can any lisp dialect do: a = c ?

Yes, for instance in Common Lisp we can make ourselves a rel macro, such that (rel a = c) evaluates a, b, c once, left to right, and then performs the comparisons between the successive evaluated terms. $ cat rel.lisp (defmacro rel (&rest args) (loop for expr in args by #'cddr for g = (gensym) collect g into gens collect `(,g ,expr) into lets finally (return `(let ,lets (and ,(loop for (left op right) on args by #'cd…

In a Lisp-1 dialect like Scheme, rel could easily and conveniently be a function. The call (rel a < b <= c) simply evaluates its arguments. The arguments < and <= are functions. The rel function then just operates on these values.

Re: Python idioms I wish I'd learned earlier

#154

Most of these idioms actually make me sad. When I first started using Python around 1999, it didn't even have list comprehensions. Code was extremely consistent across projects and programmers because there really was only one way to do things. It was refreshing, especially compared to Perl. It was radical simplicity. Over the decade and a half since then, the Python maintainers have lost sight of the language's orig…

But syntax matters! When you're writing stuff all day,

    a = [_ * 2 for _ in range(10)]
is a lot more pleasant than:

    a = []; for _ in range(10): a.append(_ * 2)
It also gives Python a lot more information about your actual intent. Suppose "range(10)" were actually "giant_list". Hypothetically, the list comprehension could pre-allocate len(giant_list) elements instead of calling list.append that many times. That's potentially a huge performance win.

You see Python as getting more complex. I see it as getting less complex by giving concise alternatives to common idioms.

Re: Python idioms I wish I'd learned earlier

#155
post #76

Some comments: 1. Am I the only one that really loves that `print` is a statement and not a function? Call me lazy, but I don't mind not having to type additional parentheses. 5. Dict comprehensions can be dangerous, as keys that appear twice will be silently overridden: elements = [('a', 1), ('b', 2), ('a', 3)] {key: value for key, value in elements} == {'a': 3, 'b': 2} # same happens with the dict() constructor dic…

"7" May be because getattr (at least) works the other way around, instead raising an exception if not found and no default specified. I'm sure many people can't always remember which works which way.

Re: Python idioms I wish I'd learned earlier

#156
post #155
post #76

Some comments: 1. Am I the only one that really loves that `print` is a statement and not a function? Call me lazy, but I don't mind not having to type additional parentheses. 5. Dict comprehensions can be dangerous, as keys that appear twice will be silently overridden: elements = [('a', 1), ('b', 2), ('a', 3)] {key: value for key, value in elements} == {'a': 3, 'b': 2} # same happens with the dict() constructor dic…

"7" May be because getattr (at least) works the other way around, instead raising an exception if not found and no default specified. I'm sure many people can't always remember which works which way.

There would be no purpose in the `get()` function if it raised an exception if the key wasn't there - that's how `[]` works. On the other hand, `getattr` is IMO mostly used for situations where you don't know what properties exist on an object, so you can't just use the dot notation.

Re: Python idioms I wish I'd learned earlier

#157
post #143
post #4

I think the example in #4 misses the point of using a Counter. He could have done the very same for-loop business if mycounter was a defaultdict(int). The nice thing about a Counter is that it will take a collection of things and... count them: >>> from random import randrange >>> from collections import Counter >>> mycounter = Counter(randrange(10) for _ in range(100)) >>> mycounter Counter({1: 15, 5: 14, 3: 11, 4:…

Python noob here. What does the _ mean in "...for _ in range(100))"?

To add to specifics:

_ in python is commonly used as a variable name for values you want to throw away. For example, let's say you have a log file split on newlines, with records like this:

    logline = "127.0.0.1 localhost.example.com GET /some/url 404 12413"
You want to get all the URLs that are 404s, but you don't care about who requested them, etc. You could do this:

    _, _, _, url, returncode, _ = logline.split(' ')
There's no special behaviour for _ in this case; in fact, normally in the interactive interpreter it's used to store the result of the last evaluated line, like so:

    >>> SomeModel.objects.all()
    [SomeModel(…), SomeModel(…), SomeModel(…), …]
    >>> d = _
    >>> print d
    [SomeModel(…), SomeModel(…), SomeModel(…), …]
Which I think is basically the same behaviour; you run some code, you don't assign it, so the interpreter dumps it into _ and goes on about its day.

Re: Python idioms I wish I'd learned earlier

#158
post #61

Earlier quoted context omitted.

It's not just a tweak to the parser, and it does have to do with the type system, but you're right that it's not about static typing. The issue is that there are languages (like C) where typing is static but weak, so e.g. booleans are also integers and can have integer operations like '>' applied to them. In other words, the problem is that in C True == 1 and 1 > 2 is a valid expression. In Python, which has strong(e…

You can implement it entirely in the parser if you can avoid name capture - it may or may not be implemented entirely as a tweak to the parser in practice, but it's fundamentally a syntactic thing. Your discussion of types here is all wrong - it's true that C treats booleans as if they were integers, but Python does, too : >>> (3 > 4) >> 3 > 4 >> 3 > (4 It has nothing to do with types.

Oh fun. That is not a nice associativity weirdness to have to deal with.

Re: Python idioms I wish I'd learned earlier

#159
post #18

Earlier quoted context omitted.

But can any lisp dialect do: a = c ?

Yes, for instance in Common Lisp we can make ourselves a rel macro, such that (rel a = c) evaluates a, b, c once, left to right, and then performs the comparisons between the successive evaluated terms. $ cat rel.lisp (defmacro rel (&rest args) (loop for expr in args by #'cddr for g = (gensym) collect g into gens collect `(,g ,expr) into lets finally (return `(let ,lets (and ,(loop for (left op right) on args by #'cd…

Anyone spot the bug? Of course

  (AND ((...) (...) ...)))
should be

  (AND (...) (...) ...)
I haven't run the generated code once, yet I can debug it: such is the power of the HN development environment.

The fix, of course, is to splice the comparison expressions into the AND:

  `(let ,lets
     (and
        ,@(loop for ... )))   ; comma splat, not comma

Re: Python idioms I wish I'd learned earlier

#160
post #141
post #101

Earlier quoted context omitted.

I love clojure for providing ( and for making = actually useful (works on nested structures properly). "Is this sorted", and "are these equal" are intuitive and useful concepts in programming and you shouldn't need to reimplement them each time you need them.

"Is this sorted" is useful but "<=" is not a good name for it.

Why? It's generalisation of binary operator , >=.
Post reply on HN