7 ms·
Python Makes Me Say God Damn
- ggchappell 16y agoIt's interesting to see how different people's complaint lists can be. I have my own list for Python (e.g., mutable/immutable/reference semantics/blah blah blah stuff messes me up all the time), but my list has almost nothing in common with the one in this article. In particular, I've thought about the first issue -- range specifications -- off & on for years, and I've come to the conclusion that this writer is wrong; Python does ranges the right way. The crux of the matter, for me, is that sometimes includes-the-end feels right, and sometimes does-not-include-the-end feels right. However, sometimes includes-the-end is definitely wrong, but I don't know of any case where does-not-include-the-end is definitely wrong. So if you're going to pick one convention, then go with the one Python did; use it all the time, and you'll never have to wonder which one you're using. It is true that this convention takes some getting used to, but I think it results in fewer bugs in the long run. Other advantages: b - a is the number of items in range(a,b); also range(a,b) and range(b,c) partition range(a,c) nicely. BTW, I believe E. Dijkstra has an essay that also takes this position on range specifications; he probably explained it a lot better than I did. As for Unicode, no one seems to know how to do it well. But this writer is talking about the Python 2 way of doing things. Python 3 has improved things, IMHO.
- baddox 16y agoThis Dijkstra essay touches on the topic. http://userweb.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html http://userweb.cs.utexas.edu/users/EWD/transcriptions/EWD08x...
- ggchappell 16y agoThat's the one I was thinking of. Thanx.
- barrkel 16y agoRange as [a, b) is definitely one of the best ways of thinking about them in the context of most algorithms. b-a is reliably the length; and when you choose a midpoint m, [a, m) and [m, b) don't overlap. Thinking in these terms makes implementing e.g. quicksort and binary search much easier.
- nailer 16y agoMy math is rusty. Could you explain your use of square and regular brackets in [a, m) and [m, b) ?
- alan-crowe 16y agoThe common useage in mathematics is in analysis and topology, to specify subsets of the real numbers. Remembering that open and closed are jargon terms in topology: (a,b) is an open set and contains exactly those x such that a is less than x and x is less than b. [a,b] is a closed set and contains exactly those x such that a is less than or equal to x and x is less than or equal to b For example, one might be thinking about the interval [0,pi] but the function 1/sin x has singularities at both ends of the interval. It is only defined on (0,pi). Notice that 1/x is defined on (0,pi]. It is sometimes convenient to mix up open=exclusive=() and closed=inclusive=[]. These conventions can be carried over into computer science in the obvious way [0,3) = {0,1,2} while (0,3] = {1,2,3} but the motivation is different. In computer science we are more concerned how smoothly our subranges chain together. For example [0,r)+[r,s)+[s,t) = [0,t) while [0,r]+[r+1,s]+[s+1,t] = [0,t]
- stevenwei 16y agoAside from the unicode thing, none of the items on that list bother me particularly much. There is one that I find really irritating though: def foo(a = []) a.append(123) or the class based version: class Foo(object): a = [] def foo(self): a.append(123) Neither example behaves like I would expect it to. For a language that espouses 'there should only be one, and preferably only one, obvious way to do it', that is not obvious to me at all! Oh, and I wish it had multi-line lambdas / blocks.
- tetha 16y agoGranted, it is not completely intuitive. However, it makes sense if you know pythons module loding mechanisms: The function definition is a statement which is evaluated at module load time, and it registers the foo-function in the module namespace. During creating the foo-function, the default-parameters are evaluated (resulting in a single list instance), and the results of this evaluation are used as default parameters in the following. That is also why something like def foo(x = random_value()) is kind of tricky and should be documented.
- zephjc 16y agofor your function example, the a=[] is not a way of initializing values per se, but is an initialized default value. If you are not passing a list reference in, and not returning anything, your function foo() without an arg does nothing. If you pass in a list reference x e.g. foo(x), x will now be [123] For your class example, this is really just a matter of remembering that any self members must be explicitly referenced as such: self.a.append(123) instead of a.append(123). I have actually grown to like this, and it helps keep it clear to others viewing your code what a ivar/method belongs to. Ruby uses @, C++ optionally uses 'this' - when I do any C++ i find myself explicitly using 'this' - its that or prefix ivars with e.g. 'm_'. Reading the Zen of Python is a good way of getting into the mindset for idiomatic Python programming
- gte910h 16y agoYeah, the def foo(a=None): if a==None: a=[] a.append(123) Is odd to get used to.
- mbenjaminsmith 16y agoPython is my favorite language, but finding a way to iterate over a list while changing the list kills me. I remember there is a good reason for Python's behavior but it always surprises me how non-intuitve a solution is.
- Luyt 16y agoPython is not unique in this regard. Consider a functional approach, where you leave the original list intact and construct a changed one.
- koenigdavidmj 16y agoList comprehensions or map are the way that a Pythonista would do this: [transform(x) for x in my_list] map(transform, my_list)
- conesus 16y agoIf iterating over a list, try iterating backwards. That way you can delete items from the list without effect on iterator position. This doesn't work on dicts, of course, but this way you can delete in-place without creating a copy data structure.
- JoelMcCracken 16y agoThere are probably 10-15 things that really bother me about python, but none of them are in this list. This list is really pretty darn awful. My biggest issue with python is its stupid tendency toward imperative programming in the standard library. For an instance of this irritation, try running python, then executing dir(<any object you pick>). Then, try dir(<obj>).sort . Notice anything? Yeah, the f'er sorted it in place, and didn't return anything. Nice job, library. I once tweeted that python was a c programmers version of lisp, and ruby is a lisp programmers version of c, and the more time I spend working with both languages, the more I am convinced of the truthfulness of this statement.
- aston 16y agoThe reason .sort() doesn't return anything is because it sorts in place. That way you won't get confused between the returned list and the sorted one. Maybe you're looking for sorted(dir(<obj>)), which gives back a new list?
- viraptor 16y agoReminds me of "Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?" Sort sorts in place. It's documented.
- viraptor 16y agoWhile I could agree with some of the points, here are some comments: range() - "Perl has trained me", well lolcode taught be that I end script with KTHNXBYE, but that's not the reason to expect it in other languages :( It's just an arbitrary choice and there's no reason to discuss about it really. Python is happy to do nothing - Meet PyLint. Perl has "use warning", python has PyLint, which will tell you that: C: 1: Black listed name "foo" W: 3: Statement seems to have no effect Unicode support is a mess - I really hate how it's done, but it definitely is not a mess. It's clean and strict. It's just hard to achieve some stuff with it. I really miss a "just give me an ascii version and ignore any errors, because I really don't care in this case" option... The rest... I can see why you might not like them, but I don't see them as design errors in any specific way.
- conesus 16y ago> I really miss a "just give me an ascii version and ignore any errors, because I really don't care in this case" option... You can use options to either ignore or replace invalid characters. >>> unicode('\x80abc', errors='strict') Traceback (most recent call last): File "<stdin>", line 1, in ? UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0: ordinal not in range(128) >>> unicode('\x80abc', errors='replace') u'\ufffdabc' >>> unicode('\x80abc', errors='ignore') u'abc'
- gte910h 16y agoUnicode was fixed....in the newest version of the language. All of us just need to switch to that unfortunately.