4 ms·
I think one of the nice things about Python is that most people write it in a similar way (with the exception of classes vs not and annotations). "There should
by rchowe 6y ago
I think one of the nice things about Python is that most people write it in a similar way (with the exception of classes vs not and annotations). "There should be one-- and preferably only one --obvious way to do it." There are already "accents" on how people write code, and the beginner dialect sounds a bit too close to Visual Basic to me.
There are some chances to smooth out some warts. I like typed languages like TypeScript, though I find Python's type system not very natural comparatively.
My biggest gripe though is that it's not possible to write functional code where you can read the operations in order. For a contrived example, if you wanted to know the total length of all strings in a list that start with the letter 'a', you would do the following in C#:
strings
.Where(s => s.StartsWith('a'))
.Select(s => s.Length)
.Sum()
Each step follows the last: first you filter the list, then you get the lengths, then you add the lengths together.
The equivalent in Python is this (I broke it out into multiple lines for a better 1:1 comparison):
sum(
len(s)
for s in strings
if s.startswith("a"))
Okay, maybe in this example the only difference is the location of the if, but in more complex example I really lose the flow by using list comprehensions.
And before anyone says I can use `map` and `filter` assign each step to a variable and write it in an "imperative-ish" style, I find it difficult to come up with descriptive names for each intermediary variable, and don't want to call them `l1`, `l2`, etc.
Gripe over, hopefully I conveyed my message.
- swagonomixxx 6y agoI agree with you that the C# example is far more readable. One thing I like about Rust is that you can implement traits on standard library types. You can imagine implementing a "Where" trait on e.g Vec<T> (btw, you don't have to, since "filter" is already there) that would return an iterator that can be used by the next method in the call chain. Unfortunately you can't "extend" standard library or built-in Python types like this. In Rust your example would be: strings.filter(|s| s.starts_with("a")).map(|s| s.len()).sum::<u32>()
- nerpderp82 6y agoThat chained syntax is entirely doable in Python. I see no reason to object to a1, a2, a3 as intermediate steps in a computation. They don't have a name in your chained style, why does the name matter with the intermediates? This is very clunky, but it is similar, could be streamlined. import aiostream from aiostream.stream import pipe import operator v = aiostream.stream.iterate(set("a ab abc ddd eeee abasdfadf".split())) \ | pipe.filter(lambda x: x.startswith('a')) \ | pipe.map(lambda x: len(x)) \ | pipe.reduce(operator.add, 0) print(await aiostream.stream.list(v))
- keithalewis 6y ago+1 for your sense of humor.
- laminatedsmore 6y agoI also like to chain functions in sequence like this, I use the toolz library to do it in Python. https://toolz.readthedocs.io/en/latest/api.html#toolz.functoolz.pipe https://toolz.readthedocs.io/en/latest/api.html#toolz.functo... "I.e. pipe(data, f, g, h) is equivalent to h(g(f(data)))"
- BerislavLopac 6y agoI disagree that the C# example is more readable. Let me just compare your own human-language description of the task with the Python code: the total length of all strings in a list that start with the letter 'a' sum( len(s) for s in strings if s.startswith("a") ) Of course that does not necessarily apply in all possible cases, but in this particular example it is practically a 1:1 match. The C# example is a better match with the way one would describe an algorithm: From a list of strings take all strings that start with the letter 'a', calculate their lengths and add them up strings .Where(s => s.StartsWith('a')) .Select(s => s.Length) .Sum() I personally find the Python's syntax much closer to natural language in most cases, which is why the language has been called "executable pseudo-code".
- majewsky 6y ago> I disagree that the C# example is more readable. You then go on to show that the Python example is closer to the English language. That doesn't prove better readability.
- BerislavLopac 6y agoFair point -- I do generally consider "readability" to be quite a subjective concept, with different people having different ideas of what is more or less readable. For me personally, code that reads like natural language is generally more readable; however a) I am aware that other people have different preferences, and b) in some cases I also prefer a more "technical" approach.
- majewsky 6y agoI might be more sensitive to this topic because I'm currently learning Japanese, which has the interesting quirk of doing several grammatical constructions backwards compared to most European languages (e.g. verbs always come at the end of the sentence). If "readable" had a correlation with "similar to English", Japanese would be utterly indecipherable.
- lightlyused 6y agoNot sure what you mean in the 2nd to the last paragraph. I really prefer using the map function: sum(map(lambda s: len(s) if s.startswith('a') else 0,['abac','bced','asdasdf','lkjkl','assadf'])) The crazy sql like syntax of your C# example bugs me a lot.
- zanellato19 6y agoThe C# example is much, much easier to read for me than yours. The else specially
- higerordermap 6y ago> sum(map(lambda s: len(s) if s.startswith('a') else 0,['abac','bced','asdasdf','lkjkl','assadf'])) I'd rather have comprehensions than map and filter that can't fit in pipeline.