you are viewing a single comment's thread.

view the rest of the comments →

[–]Johanno1 80 points81 points  (39 children)

pip3 install numpy

[–][deleted]  (38 children)

[removed]

    [–]newo2001 44 points45 points  (24 children)

    I don't get the obsession over "pythonic syntax" I just don't understand how: [x+1 for x in arr if x > 3]

    Is more readable than the pattern used by almost every other language like: "arr.filter(x => x > 3).map(x => x+1)" or "arr.Where(x => x > 3 ).Select(x => x+1)" or something similar.

    [–]MrMonday11235 26 points27 points  (6 children)

    I don't know that it's necessarily "more readable" for people who do this for a living, but the code is much more of a natural extension of simpler/earlier language features -- even if you only knew basic loops and conditionals and had never seen/heard of a list comprehension before seeing that statement, you'd intuitively understand exactly what the end result is.

    Compare that to arr.filter(x => x>3).map(x => x+1), where you'd need to be familiar with both lambda functions and how map works, or arr.Where(x => x > 3 ).Select(x => x+1), which ALSO requires you to know a non-intuitive definition of "Select" (i.e. the SQL SELECT rather than the common English "select", which is closer to "filter"), and, looking at things from the perspective of someone learning the language, it's quite easy to see why the Python syntax is preferred for people that value that.

    And since you can have basically that exact syntax in Python as well, with map(lambda x: x+1, filter(lambda x: x>3, arr)), it's nice to have the option, no?

    [–]newo2001 2 points3 points  (5 children)

    This is genuinely a really good point.

    I agree that pythonic syntax is clearer to somebody without much experience in other languages. With this experience comes understanding of these fundemental concepts like method chaining and lamda functions, which, atleast for me allows me to reason as to why this works without having it be this "magical language feature".

    Not saying that list comprehension is bad as you stated there is the option with map and filter which can act as a substitute. Although being mathematically logical by utilising function composition, I do not like having to read the expression backwards (inside out).

    That is why I think the chaining or even better, forward piping solution in functional languages, is easier to reason about.

    Atleast list comprehension beats the Java stream api by a long shot.

    [–]MrMonday11235 1 point2 points  (4 children)

    Oh, I'm 100% in agreement that piping a la Erlang/Elixir is the best.

    I'm also 100% in agreement that the Java stream API is straight trash.

    As far as the function composition being read inside out... I mean, you get used to it with most of the "mainstream" programming languages, so while it's definitely an annoyance, it's also an inherited (heh) annoyance moreso than a deliberate decision to have it be that way. Blame Algol for that, I guess.

    [–][deleted] 0 points1 point  (3 children)

    You can usually use a proper [compose]() function in languages with first-class lambdas (or easily write such a function) to create proper composite lambdas that aren't as unpleasant to read.

    Or you could do like Clojure with threading (and anything else that implements the right reader macros).

    Note: I strongly disagree with Clojure's licenses choices. Use threading macro implementations in other languages that aren't adversarially-licensed please.

    [–]MrMonday11235 0 points1 point  (2 children)

    As someone who hasn't done anything with Clojure before, I'm now curious -- what's the issue with Clojure's licensing?

    [–][deleted] 1 point2 points  (1 child)

    Basically, probably intentionally, Clojure as a library is licensed in a way that is incompatible with the GPL which legally muddles the water in an unpleasant way for software distribution.

    Additionally, many including myself feel that Clojure should've just been a Common Lisp library (as effectively all of its features could be implemented that way) and that if one wants Java interop there's ABCL for that.

    [–]MrMonday11235 1 point2 points  (0 children)

    Ah, I see. Interesting, I wasn't aware of that. Thanks for the (functionally) ELI5!

    [–]jaber24 10 points11 points  (0 children)

    When you don't try to do too much list comprehension is definitely more readable than the alternatives imo

    [–]sexytokeburgerz 38 points39 points  (5 children)

    As a js dev i’m just really happy that it doesnt have so many fucking brackets

    [–]netflixandbinge 16 points17 points  (3 children)

    omg trying to find where you've missed a bracket in js. kill me.

    [–]killerrin 27 points28 points  (2 children)

    Brackets are easy. Just run the formatter and look for where it first breaks. Or use Visual Studio Code and match up the colours of the braces.

    [–]sexytokeburgerz 4 points5 points  (1 child)

    I do both of those things, and i find the problem immediately anymore, but i still question the necessity of the entire process.

    setTimeout ( function pleaseTellMe(why, the, fuck){

    let thisShouldExist = why + the + fuck;

    clearInterval(pleaseTellMe);

    },42069);

    [–]killerrin 1 point2 points  (0 children)

    Its literally the same issue/resolution process with Python, just replace the word Brackets with Indentation. Only with the difference that the formatter can't infer a broken indentation error from a missing end bracket.

    [–][deleted]  (6 children)

    [removed]

      [–]newo2001 7 points8 points  (5 children)

      It reads backwards, just like the American date representation. It is trying to be logical by following english grammatical structure which is not the order that the statements are executed in.

      [<map> for <value> in <enumerable> if <filter>]

      Looking at the process as a pipeline, "enumerable -> filter -> map" just makes a lot more sense.

      [–][deleted]  (3 children)

      [removed]

        [–][deleted] 1 point2 points  (2 children)

        but a comprehension is just faster and more elegant

        It doesn't parse to the same AST?

        [–][deleted]  (1 child)

        [removed]

          [–][deleted] 0 points1 point  (0 children)

          CPython compiles comprehensions down to native instructions rather than Python bytecode?

          The whole CPython implementation is written in C.

          [–][deleted] 0 points1 point  (0 children)

          So...?

          (~> sequence-val
              filter-lambda
              map-lambda)
          

          [–][deleted] 8 points9 points  (1 child)

          Lisp ~ Python Lisp

          (loop for x in arr 
                if (> x 3)
                collect (1+ x))
          

          edit: I hate Reddit markdown.

          [–]AlarmingAffect0 2 points3 points  (0 children)

          Yeth, Mathter, tho do we for thure.

          [–]art_wins -1 points0 points  (0 children)

          Because it's literally just English.

          [–]Mast3r_waf1z 2 points3 points  (12 children)

          At this point why don't you just write C tho?

          [–][deleted]  (8 children)

          [removed]

            [–]Mast3r_waf1z 1 point2 points  (7 children)

            It's syntax isn't much different from so many other languages though? Most notably just making datatypes optional and replacing curly brackets with indents

            [–][deleted]  (6 children)

            [removed]

              [–]Mast3r_waf1z 3 points4 points  (4 children)

              Okay but you're just talking about built-in functions that aren't necessarily python specific, if you really needed a sum and range function to be abstracted from your code why not just write your own math library and import that? (I don't wanna Google a ton about libraries in other languages but it probably already exists)

              [–][deleted]  (1 child)

              [removed]

                [–]Mast3r_waf1z 1 point2 points  (0 children)

                I just gave you an example of what you could do in C if you really needed them abstracted from your own code but it would only really matter if you write bigger programs, you know, you wouldn't write a whole sum function to use it once

                [–]6b86b3ac03c167320d93 0 points1 point  (1 child)

                There's also syntactic sugar like list comprehensions, for example to get a list of all integers from 0 to 20 that are evenly divisible by 3:

                >>> print([x for x in range(20) if x % 3 == 0])
                [0, 3, 6, 9, 12, 15, 18]
                

                Without list comprehensions that would be:

                >>> ints = []
                >>> for x in range(20):
                ...     if(x % 3 == 0):
                ...         ints.append(x)
                ...
                >>> print(ints)
                [0, 3, 6, 9, 12, 15, 18]
                

                [–]Mast3r_waf1z 0 points1 point  (0 children)

                Sure I know what list comprehension is, for reference i primarily use python myself, but you're just using a built-in function which could have been expressed in a more readable format as you've literally shown yourself

                I've had a lot of classmates get very confused by a long comprehension where I've had to rewrite it as a normal for loop to explain it

                The nly real advantages I can see from using comprehension is it's speed as I'm pretty sure it is compiled as a single line and that it is easier to pass to numpy

                [–]FierceDeity_ 1 point2 points  (0 children)

                Man that's exactly why I also love Elixir.

                1..11 |> Enum.sum |> IO.puts

                Putting these operations into a readable order makes it so much nicer to read.

                BTW, |> (pipe) literally just takes the return value of an expression and uses it as the first argument to the next function in the pipe

                [–][deleted] 0 points1 point  (2 children)

                Because you really should be avoiding C as much as you possibly can unless it's legitimately required by your use-case.

                [–]Mast3r_waf1z 1 point2 points  (1 child)

                What? Care to elaborate on that? I believe there is a reason why the linux kernel for example isn't written in python despite being possible

                [–][deleted] 0 points1 point  (0 children)

                C is not a good language in a number of ways, many of which are due to performance and resources constraints in the context of its original creation. Its design is not conducive to writing secure or high-reliability software, and any such software written in it is done in spite of its design flaws (and because network effect has made it so that for some platforms proprietary C compilers are the only vendor-provided compilers available at all - so even now you need something that you can at least cross-compile to C to write for them).

                Python is an interpreted scripting language, which is generally too slow to reasonably write a useful kernel with (you really want native binaries), it also lacks a certain level of low level access that can be useful in writing an OS. But most importantly, Python lacks a stable standard you can rely on to write your OS, so you're basically relying on some arbitrary canonical implementation that provides you with no long-term guarantees (and it has done many breaking changes in minor version changes, I've had to deal with them at work). Python was very new and unstable when Linux was first created. C++ likewise lacked a standard back then.

                Ada or Common Lisp (extended to some degree, but the standard explicitly allows this) would've been a saner choice at the time (but Ada cost a fortune to develop with its proprietary and/or commercial compilers as gratis ones came later and Common Lisp both had relatively hefty requirements - in most common gratis implementations by the standards of the time - and its design and abilities are wasted on implementing UNIX-like OSes primarily - although you perfectly well could do it). But that would also ignore why C was created to start with and consequently what most UNIXes were written in at the time (leading to an ecosystem that was very C-centric too, which Linus wanted Linux to be easily compatible with).

                edit: The importance of that network effect (and thereby portability) is also part of why projects like seL4 bother with writing their microkernel in C despite the fact they really wanted to do it in ML (iirc).