Live data from Hacker News

WTFPython – Understanding Python through surprising snippets

github.com

81–90 of 199 posts

Re: WTFPython – Understanding Python through surprising snippets

#81

Earlier quoted context omitted.

This is most probably because you are trying to code in Python like you code in JS: this always leads to frustration. I started to have fun coding in JS the day I accepted it was not Python and that I had to structure and style my code differently. E.G: in Python you will use iteration a lot. A lot of a lot. But not so many callbacks. The reverse is true in JS.

Iterators and callbacks aren’t comparable. You don’t use them for the same thing.

What do you think each(), map() and filter() do ?

But even without that, I'm not saying they are comparable. I'm saying the same API will use explicit anonymous callbacks in JS and something else in Python (decorators, subclassing, protocols, generators...). I'm saying that the same API will use __iter__ in Python and something else in JS (type conversion, proxy object, explicit method call...).

E.G, this is a Python pattern you'll find in contextlib or in pytest fixtures:

    @somekindofregistration
    def foo():
        print('code that runs before')
        try:
            yield
        except Stuff:
            print('Error handling')
        print('code that runs after')
This uses Python iteration mechanism to run code at 3 different times in a life cycle.

While in JS, you would pass 3 callbacks.

Re: WTFPython – Understanding Python through surprising snippets

#82
post #55

Earlier quoted context omitted.

in the zen of python (import this) it says: there should be one-- and preferably only one --obvious way to do it. sadly this is not true for a while in python now. Python became a language that can be really hard to read now.

> there should be one-- and preferably only one --obvious way to do it. Yes, this has been one of the hardest balance to find. And believe me when I tell you the community tries very, very hard. But it's a difficult problem: making the language evolves fast enough, but keeping it solid and stable. Very difficult indeed. > Python became a language that can be really hard to read now. Not in my experience. My job invol…

The new walrus operator now makes indentation obsolete. You can write averything within one line as an array and it is hard to read. This in combination with syntactic sugar, operator overloading and unicode variables can make the language very hard to read.

e.g.

  # compute pi
  1000000 >> ψ( ψ(χ>>op("(x**2+y**2)**0.5>Σ*4>> _/_)
or this:

  # 10 fibonacci numbers
  [x:=[1,1]] + [x := [x[1], sum(x)] for i in range(10)]

is valid python code. (for the first see my github jamitzky/iverson). Not that I wouldnt like it, but python3 has changed and the zen of python is not valid for some time now.

Re: WTFPython – Understanding Python through surprising snippets

#83
post #57

Earlier quoted context omitted.

I was thinking more of the case where the types match but objects and arrays with the same contents are considered different. I’ve watched every member of my team get stung by it again and again - and then have to create workarounds to get past it.

I don’t agree and this behavior shouldn’t be surprising. The alternative would be to walk the container and compare the value of each element, which could be horrible.

Quite the contrary, it's very beautiful and useful:

    >>> (1, 2) == (1, 2)
    True
    >>> (2, 1) == (1, 2)
    False
If you need identity for perf:

    >>> (1, 2) is (1, 2)
    False
If you just need the type check:

   >>> isinstance((1, 2), type((1, 2)))
   True
It's very explicit, practical, and you can set the scale of practicality vs performances where you want. Plus: no implicit weird type conversion, only one equality comparison operator, and no hidden rules.

I think it's sane.

Re: WTFPython – Understanding Python through surprising snippets

#84
post #8

My biggest complaint about Python is that it somehow doesn’t get flak for having the same (if not worse) scoping as JS, which gets endless hate for its function-scoped variables. (So much so that block scoped variables are the new normal in JS, but not in Py!) Take for instance: >>> powers_of_x = [lambda x: x^i for i in range(10)] >>> [f(2) for f in powers_of_x] [512, 512, 512, 512, 512, 512, 512, 512, 512, 512] To m…

[deleted]

Re: WTFPython – Understanding Python through surprising snippets

#85
post #8

My biggest complaint about Python is that it somehow doesn’t get flak for having the same (if not worse) scoping as JS, which gets endless hate for its function-scoped variables. (So much so that block scoped variables are the new normal in JS, but not in Py!) Take for instance: >>> powers_of_x = [lambda x: x^i for i in range(10)] >>> [f(2) for f in powers_of_x] [512, 512, 512, 512, 512, 512, 512, 512, 512, 512] To m…

You can achieve the same thing in python by using two lambdas (which is actually what you're doing in JS with map):

   >>> powers_of_x = [(lambda i: (lambda x: x**i))(i) for i in range(10)]
   >>> [f(2) for f in powers_of_x]
   [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
Or you can use default parameter values to use a single lambda (though this means it can be overridden, it's not semantically equivalent to the js implementation)

   >>> powers_of_x = [lambda x, i=i: x**i for i in range(10)]
   >>> [f(2) for f in powers_of_x]
   [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
your python snippet is equivalent to the following JS:

   >>> function* comprehension(iterable){
   >>>   let i;
   >>>   for(let j of iterable){
   >>>     i = j;
   >>>     yield x => x**i;
   >>>   }
   >>> }
   >>> powersOfX = [...comprehension([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])];
   >>> powersOfX.map(f => f(2))
   [512, 512, 512, 512, 512, 512, 512, 512, 512, 512]
And Python's comprehensions are actually a shorthand for writing the above generator with this syntax: yieldExpression for i in iterable. The semantics are consistent with the regular for..in

   >>> def comprehension(iterable):
   >>>     for i in iterable:
   >>>         yield lambda x: x**i
   >>> [*comprehension(range(10))]
is equivalent to

   >>> [lambda x: x**i for i in range(10)]
This is all a consequence of python's late binding.

Re: WTFPython – Understanding Python through surprising snippets

#86
post #71

Earlier quoted context omitted.

Yeah, current versions of Python feel like Guido and the rest changed their minds about what they wanted.

I think Python’s direction changed when Guido moved to Dropbox. Suddenly he was working on a million-line Python codebase, and started working to make the language more suitable for programming in the large.

Yeah, that certainly fits.

Re: WTFPython – Understanding Python through surprising snippets

#87

It's a good repo, but remember a lot of those are "A Good Thing™". The first snippet is a very good example: a := "wtf_walrus" doesn't work while: (a := "wtf_walrus") works. It's a fantastic design decision. Python took a long time before getting this operator, because it's a language that favors being readable, easy to use, and above all, to learn. But in many other languages, the very same operator is often misused…

Why should people only use it when necessary? Why not say “the walrus operator is the exact same as the assignment operator, but it can be used in expressions and thus is spelled a bit differently in order to better distinguish it from the equality operator. Feel free to use it in all places you’d previously use the assignment operator.”. Simple, easy to understand, easy to learn, and most importantly (though python folks might disagree, given 2 => 3), easy to adopt. (Find and replace all single equals with colon equals and you’re done).

Instead, they’ve chosen the narrative: “the walrus operator is a lot like the assignment operator, but it is able to be used in expressions, cannot be used as a statement, and it sits below the comma operator in precedence instead of above it. We understand that this is super confusing, so use it sparingly”.

One way you have two operators for people to learn, with the understanding that there is a third legacy operator that works pretty much the same as one of them. The way they chose you have three operators for people to learn, with two of them behaving pretty similarly but not interchangeably, and with subtle yet important differences.

Re: WTFPython – Understanding Python through surprising snippets

#88
post #57

Earlier quoted context omitted.

I was thinking more of the case where the types match but objects and arrays with the same contents are considered different. I’ve watched every member of my team get stung by it again and again - and then have to create workarounds to get past it.

I don’t agree and this behavior shouldn’t be surprising. The alternative would be to walk the container and compare the value of each element, which could be horrible.

I’m not sure if you’re for or against here. Walking the container is exactly what you have to do, and it is horrible. More importantly, if it’s not your library, you don’t get any choice on how the equality check is implemented.

Re: WTFPython – Understanding Python through surprising snippets

#89
post #82

Earlier quoted context omitted.

> there should be one-- and preferably only one --obvious way to do it. Yes, this has been one of the hardest balance to find. And believe me when I tell you the community tries very, very hard. But it's a difficult problem: making the language evolves fast enough, but keeping it solid and stable. Very difficult indeed. > Python became a language that can be really hard to read now. Not in my experience. My job invol…

The new walrus operator now makes indentation obsolete. You can write averything within one line as an array and it is hard to read. This in combination with syntactic sugar, operator overloading and unicode variables can make the language very hard to read. e.g. # compute pi 1000000 >> ψ( ψ(χ>>op("(x**2+y**2)**0.5 >Σ*4>> _/_) or this: # 10 fibonacci numbers [x:=[1,1]] + [x := [x[1], sum(x)] for i in range(10)] is va…

You could do that with a lambda since Python 2.4.

E.G, calculating primes:

    >>> print(list(filter(None,map(lambda y:y*__import__('functools').reduce(lambda x,y:x*y!=0, map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))))
    [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
As for the unicode caracters as variables... Remember you could do that in Python 2 ?

    # -*- coding: rot13 -*-

    cevag "Relax"

But people don't do it. Just like they don't use "import *" everywhere, or monkey patch methods like it's going out of style the way Ruby loved it 15 years ago.

Because such capabilities are restricted (one line lambda, parenthesis for walrus, not all unicode is allowed as var names or everywhere...), introduced slowly, and the community culture is to value readability, Python stays Python.

I was against the walrus personally, for the reasons you mention. But while I do see Raymond Hettinger trolling twitter regularly with his latest crazy walrus magic, in production we see no such thing.

Not to say it never happens. It does, I've seen monstrosities in the field. Like with every tech. I mean, you can start a fire with a water hose if you try hard enough.

But it's rare.

Re: WTFPython – Understanding Python through surprising snippets

#90
post #71
post #55

Earlier quoted context omitted.

in the zen of python (import this) it says: there should be one-- and preferably only one --obvious way to do it. sadly this is not true for a while in python now. Python became a language that can be really hard to read now.

Yeah, current versions of Python feel like Guido and the rest changed their minds about what they wanted.

Python is a very old language. First version in 1991!

This is no surprise Guido evolved with it, and changed his mind about a few things.

People are never happy. On the other side of the fence, you have others crying the language is not moving fast enough.

Post reply on HN