Hacker News new | ask | show | jobs
by FZ1 2291 days ago
A key hallmark of Python is readability - which this cheat sheet has managed to royally screw up.

It looks more like an XML cheatsheet at first glance.

I work in python full-time for a living, and found myself having to re-examine several times to make sense of this wacky, non-standard notation.

-------

Edit:

Keep in mind there's a standard way to represent these options in a clear, consistent manner (lists, sequences, optional args).

No need to re-invent something that's hard to read and understand.

See: https://docs.python.org/3/library/stdtypes.html#sequence-typ...

3 comments

I think this is for people who already know Python, and just need a quick memory aid. I agree for a complete and correct reference I would recommend the documentation, as you said.

A proper cheatsheet takes liberties for the sake of achieving both brevity and comprehensiveness at the same time.

While I agree the notation is a bit weird, I disagree that there is any standard notation for types. The Python docs in particular fail for exactly one of the things I like about TFA - it tells you the type of the output of each function in its angle-bracketed style.

Take, for example, the definition of the operation s[i:j] in the Python docs: the result is "slice of s from i to j". Is that the same type as the input? Is it an iterator? No information.

I doubt most people are confused about the output, but a reference is specifically for people who are uncertain about how a function works.

You're right that there is not any official standard.

But almost every major library follows a convention that's very similar to the cpython docs.

If you're making a language reference, shouldn't it look like the language ?

the hallmark is readability?! really!?

Please explain to me why then you introduce a binding after you use it in array comprehensions.

    [x*2 for x in range(1,10)]
In one of your math courses you'll eventually run across what they call "set builder notation.

The notation for this is a decent example that shouldn't be too hard to follow. What it's basically saying is

{2x: x∈[1,10)}

with the implication that x is an integer. We usually read the colon (or sometimes a vertical bar) as "such that". I know my explanation is somewhat lacking, but you can probably see the parallels there. You'll probably get to it this year or next.

I'm very aware of set builder notation, and also not a fan. I mean it beats a lot of other things mathematicians were probably doing before they agreed to it, but it's still not ideal in my eyes.

My example (formatted again below), is probably an interesting middle ground, because both the left and right are only mildly interesting. While most often (not always) in math I've seen the right be "trivial".

    trivial right: { 2x : x ∈ ℝ }
    mildly interesting right: { 2x : x ∈ [1,10) }
    complex right: { 2x : x ∈ [0, ∞].filter(...) }
In the top two cases, things aren't so bad. But as we digress to the third case I fear we'd be better of like:

    [0, ∞].filter(...).map(|x| 2x)
This is generally how I'd solve the issue. I've made a point of avoiding talking about nested array comprehensions, since these get completely impossible to reason about statically for me.

EDIT: Just because I' on a bit of a rant ATM, I might as well complete it...

In Rust we also have where clauses, however you still must at least introduce the name up front. For example:

    fn foo<A>(..., a: A, ...) where A: ...
This solves the problem of name resolution in my head while I try and read this function, since there's always a namespace you're operating within. Without the leading `<A>` I'd be left wondering WTF `a: A` means.
As a person who majored in math, this is very readable.
As a person who often struggled in math for perhaps many reasons, this was a common issue for me.

First you define things, then you use them.

No other rule makes sense generally, and I challenge anyone to prove me wrong.

Now is a simple set like { 2x : x ∈ ℝ } going to confuse me, probably not... but when variables are just thrown around all willy nilly, I get confused pretty quick.

I never understood list comprehensions, and was always slightly resentful of (in my mind) their illogical ordering until I realized they were mimicking mathematical expressions.
Functional programming?
I wouldn't call this a functional argument, per se, although many functional languages encourage the kind of syntax I'm advocating for here. And some may not...

Basically I write things like `data.map(|x| ...).filter(|x| ...)`, or just `data.fold(|x| ...)` and I'm quite happy.