147

Python seems all the rage these days, and not undeservingly - for it is truly a language with which one almost enjoys being given a new problem to solve. But, as a wise man once said (calling him a wise man only because I've no idea as to who actually said it; not sure whether he was that wise at all), to really know a language one does not only know its syntax, design, etc., advantages but also its drawbacks. No language is perfect, some are just better than others.

So, what would be in your opinion, objective drawbacks of Python.

Note: I'm not asking for a language comparison here (i.e. C# is better than Python because ... yadda yadda yadda) - more of an objective (to some level) opinion which language features are badly designed, whether, what are maybe some you're missing in it and so on. If must use another language as a comparison, but only to illustrate a point which would be hard to elaborate on otherwise (i.e. for ease of understanding)

Teun Zengerink
  • 127
  • 1
  • 1
  • 4
Rook
  • 19,861
  • 9
  • 53
  • 96
  • 50
    I think that this is a helpful subjective question, and it would be a shame to close it. – Eric Wilson Oct 29 '10 at 00:09
  • 1
    @FarmBoy - Well, I certanly tried to form it as such. Too bad the closer didn't leave a comment elaborating why he feels it is not constructive. – Rook Oct 29 '10 at 00:12
  • @Xepoch: Every language I've ever used has whitespace as tokens in its grammar. –  Oct 29 '10 at 06:00
  • @Xepoch - I ment - why he feels the question is not constructive. – Rook Oct 29 '10 at 09:28
  • 25
    There seems to be a python-fanboy here who just downvotes all anti-python answers. – zvrba Oct 29 '10 at 09:54
  • 1
    @zvrba: You get two downvotes and resort to name calling. Don't worry, you're still net positive rep. –  Oct 29 '10 at 14:25
  • 1
    @Roger: whitespace as tokens, or token delimiters? Most lexers I've worked with strip out whitespace and don't even pass it to the parser. – TMN Oct 29 '10 at 16:12
  • 2
    @TMN: That's still treating the whitespace as tokens, just not returning them — and it's exactly what Python's grammar does too. –  Oct 29 '10 at 16:22
  • 9
    @Roger: the convention on SO is to comment downvotes. Since this is a site for *subjective* opinions, I see no reason for downvotes, esp. w/o comments. So, I stand by my "name-calling". – zvrba Oct 29 '10 at 20:48
  • 8
    @zvrba: Downvotes still mean "not useful", just as always. –  Oct 30 '10 at 02:32
  • 2
    What exactly is an "objective opinion"? – Brendan Long Jul 23 '11 at 23:29
  • @Brendan Long: I think in this case "objective opinion" is an opinion that acknowledges its own limitations. – oosterwal Jul 24 '11 at 02:26
  • ahah, 2 years old thread revived by hackernews. The funny thing is that I tend to see many of the drawbacks listed here as a feature. Is my mind distorted ? – vincent Sep 08 '12 at 16:16

24 Answers24

109

I use Python somewhat regularly, and overall I consider it to be a very good language. Nonetheless, no language is perfect. Here are the drawbacks in order of importance to me personally:

  1. It's slow. I mean really, really slow. A lot of times this doesn't matter, but it definitely means you'll need another language for those performance-critical bits.

  2. Nested functions kind of suck in that you can't modify variables in the outer scope. Edit: I still use Python 2 due to library support, and this design flaw irritates the heck out of me, but apparently it's fixed in Python 3 due to the nonlocal statement. Can't wait for the libs I use to be ported so this flaw can be sent to the ash heap of history for good.

  3. It's missing a few features that can be useful to library/generic code and IMHO are simplicity taken to unhealthy extremes. The most important ones I can think of are user-defined value types (I'm guessing these can be created with metaclass magic, but I've never tried), and ref function parameter.

  4. It's far from the metal. Need to write threading primitives or kernel code or something? Good luck.

  5. While I don't mind the lack of ability to catch semantic errors upfront as a tradeoff for the dynamism that Python offers, I wish there were a way to catch syntactic errors and silly things like mistyping variable names without having to actually run the code.

  6. The documentation isn't as good as languages like PHP and Java that have strong corporate backings.

dsimcha
  • 17,224
  • 9
  • 64
  • 81
  • @dsimcha: "Nested functions kind of suck in that you can't modify variables in the outer scope". Do you mean that it doesn't have closures? – Merlyn Morgan-Graham Oct 28 '10 at 23:01
  • 2
    Python does have closures. – Adam Crossland Oct 28 '10 at 23:14
  • 1
    #2: You can modify variables in the outer scope by using the nonlocal statement in python 3. #3: Python simply has no value types in that sense. Even numbers are just immutable objects. – Winston Ewert Oct 29 '10 at 00:47
  • Clarification: Python does have closures. The thing I don't like about them is that, if you have an outer function and an inner function, you can't use the inner function to modify variables local to the outer function. You only have read-only access. – dsimcha Oct 29 '10 at 00:51
  • @Winston: Thanks for the note about Python 3. I was completely unaware of this, as one of my major reasons for using Python when I use it is library support. Needless to say, this means I still use Python 2. – dsimcha Oct 29 '10 at 01:00
  • @dsimcha: The workaround for nonlocal in 2.x is annoying, but seamless: make the outer variable a list and always use var[0]. –  Oct 29 '10 at 06:02
  • 60
    @Casey, I have to disagree. The index is horrible - try looking up the `with` statement, or methods on a `list`. Anything covered in the tutorial is basically unsearchable. I have much better luck with Microsoft's documentation for C++. – Mark Ransom Oct 29 '10 at 06:14
  • 17
    About 5 - just use pyflakes. It's written to catch exactly those errors. – Alexander Solovyov Jul 12 '11 at 09:13
  • 4
    Regarding speed: with the rise of PyPy, many Python users will now be able to handle the speed problem just by using an interpreter with a built in JIT-compiler (for now, Python 3 users and users of C extension modules not handled by cpyext do not have this option). – ncoghlan Jul 13 '11 at 03:07
  • 1
    Regarding documentation: Are these comments related to the current Sphinx-based documentation? Or are they related to the pre-Sphinx documentation? The former seems unlikely, as those have excellent indices and search capability, but they would be perfectly understandable for the latter. – ncoghlan Jul 13 '11 at 03:10
  • 2
    The most valid comment in this set is number 4. Python is *not* a low level systems programming language. Far better to reach for an appropriate tool (such as C) and use your Python code to manage the higher level stuff. – ncoghlan Jul 13 '11 at 03:17
  • 29
    I despise the Python docs. They're prettier than most to be sure, but many times a lot of useful information is lumped into one page, like methods on strings and lists -- and all the sequence types are lumped together as well. When I search this information, I just land on a huge tome, and have to search down the page to find what I want. I also find the index on these pages hard to read, and it's sometimes difficult to tell which section I want. – Carson Myers Jul 23 '11 at 01:53
  • 3
    "Slow"? Slow at what? Compared to what? – dbr Sep 08 '12 at 12:50
  • 1
    regarding 4 - you could always code performance critical segments in c/c++ and use it from python .. – Protostome Sep 08 '12 at 15:14
  • "Slow" - have you tried PyPy? Sure it's not a silver bullet, but it sorts out those "need another language" parts. – fijal Sep 08 '12 at 16:02
  • 5
    How can distance from the metal be an argument? Did Python ever purport itself to be a systems language? – Mark Canlas Sep 09 '12 at 00:01
66

I hate that Python can’t distinguish between declaration and usage of a variable. You don’t need static typing to make that happen. It would just be nice to have a way to say “this is a variable that I deliberately declare, and I intend to introduce a new name, this is not a typo”.

Furthermore, I usually use Python variables in a write-once style, that is, I treat variables as being immutable and don’t modify them after their first assignment. Thanks to features such as list comprehension, this is actually incredibly easy and makes the code flow more easy to follow.

However, I can’t document that fact. Nothing in Python prevents me form overwriting or reusing variables.

In summary, I’d like to have two keywords in the language: var and let. If I write to a variable not declared by either of those, Python should raise an error. Furthermore, let declares variables as read-only, while var variables are “normal”.

Consider this example:

x = 42    # Error: Variable `x` undeclared

var x = 1 # OK: Declares `x` and assigns a value.
x = 42    # OK: `x` is declared and mutable.

var x = 2 # Error: Redeclaration of existing variable `x`

let y     # Error: Declaration of read-only variable `y` without value
let y = 5 # OK: Declares `y` as read-only and assigns a value.

y = 23    # Error: Variable `y` is read-only

Notice that the types are still implicit (but let variables are for all intents and purposes statically typed since they cannot be rebound to a new value, while var variables may still be dynamically typed).

Finally, all method arguments should automatically be let, i.e. they should be read-only. There’s in general no good reason to modify a parameter, except for the following idiom:

def foo(bar = None):
    if bar == None: bar = [1, 2, 3]

This could be replaced by a slightly different idiom:

def foo(bar = None):
    let mybar = bar or [1, 2, 3]
Konrad Rudolph
  • 13,059
  • 4
  • 55
  • 75
  • Immutable variables can be done with class attributes -- see [this](http://www.ibm.com/developerworks/linux/library/l-prog2.html) article, at the beginning, the section "Bindings". – Abbafei Mar 17 '11 at 22:39
  • 6
    I so so wish Python had a "var" statement. Besides the (very good) reason you state, it would also make it a lot easier to read the code because then you can just scan over the page to spot all the variable declarations. – jhocking Jul 11 '11 at 23:19
  • 25
    It is as if the python developers ignored the lessons of the past. Not declaring variables, not declaring functions, is a mistake first made in the 1950s. Those hard to find bugs that resulted from a hard to spot typo were amazingly enough first made in the 1950s. This language mistake has been made (and later corrected) time and time again. Declaring variables is not a huge burden. It has saved my butt multiple times. I inevitably `use strict;` and `use warnings;` in perl on a script of any size. Python has stripped the developer of far too many debugging aids. – David Hammen Jul 19 '11 at 00:00
  • 19
    @David, To be fair to python, it will raise an exception if you try to access a variable which has not been assigned to. Many of the languages which lack declarations would return some sort of default value. As a result, Python's version is much less problematic then those ones. – Winston Ewert Jul 23 '11 at 23:58
  • I can only imagine the features `let` and `var` with some kind of notation to enable strict checks otherwise you break *all* existing code. That notation could work on a function/class/module level to note that checks should be enforced. – Karoly Horvath Jul 24 '11 at 00:20
  • I can't edit, but `let y # Error: Declaration of read-only variable `x` without value` uses the wrong var (x should by y) – Martijn Jul 24 '11 at 00:42
  • 1
    @yi_H The proposal wasn’t meant to be backwards compatible – or even a real proposal. The question was, “what are the drawbacks of Python” … well, not having `var` and `let` (or a similar mechanism) is a drawback. Put differently: had I been the designer of Python, I would have done something like this. *That said*, future versions *could* include this when you load a special package (similar to `__future__`). Say, `import strict`. This won’t happen though, since it requires syntactical hacks … – Konrad Rudolph Jul 24 '11 at 13:48
  • Is there any popular dynamic language out there which is using these strict checks? I think Perl is the only one, but gets less and less popular. PHP and Ruby doesn't do it and Javascript is the worst of all of them since it puts the non-declared variables into global scope, which can lead to very ugly bugs. I'm more or less satisfied with the rest (non JS) languages, if you ever write test-cases to your code (which you should do anyway) you will catch 99% of the typos. I'm not saying I wouldn't enjoy a strict mode for some tasks but it's probably a feature I can live without. – Karoly Horvath Jul 24 '11 at 15:38
  • @yi_H Not that I’m aware of. I’d use it in a heartbeat – well, not Perl since that is just FUBAR. I do use Perl but I don’t relish it. As for test cases: obviously these help but I hate writing manual tests for issues that the compiler should (and could!) catch for me. This is what a type system is there for, after all. My C++ projects have (near) 100% test coverage but I don’t have to write redundant tests to get rid of errors that the type system will catch. – Konrad Rudolph Jul 24 '11 at 15:47
  • @David is right about declarations, but there is an argument that most languages that require those declarations go too far the other way. There are interesting middle-grounds in static typing, and some are certainly possible (don't know any implementation) for dynamic languages. But it's not that surprising that people rejecting one extreme jump straight to the opposite extreme. –  Jul 25 '11 at 22:50
  • It's perhaps less disruptive to use const for read-only variables. – Seun Osewa Nov 30 '11 at 18:12
  • @Seun I don’t think so. On the contrary. – Konrad Rudolph Nov 30 '11 at 18:48
  • 3
    +1 For adding better 'functional-like' programming abilities. – Evan Plaice May 02 '12 at 14:33
  • @WinstonEwert - Perhaps but then you're just hoping that the block of code which references that variable happens to be called and yo can catch it at runtime... – Basic May 29 '13 at 14:38
  • @Basic, if your testing has never run that block of code chances are its broken in more ways than just having a misspelled variable name. – Winston Ewert May 29 '13 at 14:44
  • 1
    @WinstonEwert So now we need to run the whole set of unit tests to find a typo... – Basic May 29 '13 at 15:03
  • @Basic, the point of my comment was that raising an exception is way better than treating all undeclared variables as NULL. As you'll see in my comment, I described it as much less problematic. I was reacting to the previous comment that claimed that Python was just repeating the same mistake as older languages, which I think was over-simplifying the issue. – Winston Ewert May 29 '13 at 16:24
  • 1
    @Basic, actually, it is possible to detect many of those typos without actually running the code. Pylint, pyflakes, and pychecker can all statically analyze code and detect those errors. – Winston Ewert May 29 '13 at 16:26
44

My main complaint is threading, which is not as performant in many circumstances (compared to Java, C and others) due to the global interpreter lock (see "Inside the Python GIL" (PDF link) talk)

However there is a multiprocess interface that is very easy to use, however it is going to be heavier on memory usage for the same number of processes vs. threads, or difficult if you have a lot of shared data. The benefit however, is that once you have a program working on with multiple processes, it can scale across multiple machines, something a threaded program can't do.

I really disagree on the critique of the documentation, I think it is excellent and better than most if not all major languages out there.

Also you can catch many of the runtime bugs running pylint.

dbr
  • 161
  • 5
cmcginty
  • 729
  • 5
  • 10
  • 2
    +1 for pylint. I was unaware of it. Next time I do a project in Python, I'll try it out. Also, multithreading seems to work fine if you use Jython instead of the reference CPython implementation. OTOH Jython is somewhat slower than CPython, so this can partially defeat the purpose. – dsimcha Oct 29 '10 at 00:48
  • 3
    Threading is not well supported? The threading libraries have been in there since before 2.1. – rox0r Dec 18 '10 at 07:16
  • 2
    I know there is threading support, but compared to Java or C, the GIL will really lower your performance. That is why the multiprocessing module is preferred over threading. – cmcginty Dec 20 '10 at 23:15
  • 2
    The documentation is good if you can manage to find it. Googling Java classes is *much* easier than Python. – Brendan Long Jul 23 '11 at 23:32
  • @Casey I've clarified the wording in the answer, since threading is supported, just exhibits some weird performance (added a reference and a few links to docs too) – dbr Sep 08 '12 at 13:05
  • This is really more a critique of the interpreter than the language. My understanding is that Jython bypasses the GIL and uses Java Threads, which typically are system threads. – philosodad Sep 08 '12 at 18:32
  • Nevertheless so many real world Python app has module dependencies that tie it to CPython and native CPython extensions, that JYthon is immaterial to real Python use. Does Mercurial run in Jython, for instance? – Warren P Sep 11 '12 at 03:17
28

Arguably, the lack of static typing, which can introduce certain classes of runtime errors, is not worth the added flexibility that duck typing provides.

Jacob
  • 382
  • 3
  • 14
  • 5
    This is correct, though there are tools like PyChecker which can check for errors a compiler in languages like C/Java would do. – Oliver Weiler Oct 28 '10 at 23:42
  • 24
    Dynamic typing is a conscious design decision, not a drawback. – missingfaktor Nov 11 '10 at 12:18
  • 14
    Its the same as saying Java's weakness is lack of dynamic typing. – MAK Nov 11 '10 at 13:36
  • 12
    @missingfaktor, @MAK, *obviously* duck typing was an intended feature. But most design decisions introduce objective benefits and drawbacks. The added code flexibility is a benefit of dynamic typing, and the additional classes of potential runtime errors is a drawback. The subjective part is whether the feature is worth it. – Jacob Nov 11 '10 at 16:27
  • Lack of static typing introduces runtime errors? – rox0r Dec 18 '10 at 07:17
  • 6
    Lack of static typing makes it easier for *programmers to write code* that has runtime errors. In C#, `int foo = 4; Console.Write(foo.Length);` doesn't compile, so the error "Int32 doesn't have a property Length" cannot accidentally make its way into published software. In python, unless you run optional secondary tools to look for errors like that, code that accesses non-existing members of objects can go undetected until it ends up causing runtime errors. – Jacob Dec 18 '10 at 16:29
  • 1
    See [this](http://code.activestate.com/recipes/577299-method-signature-type-checking-decorator-for-pytho/) for a feature similar to "static types" for Python 3, and [this](http://code.activestate.com/recipes/426123/) for Python 2. – Abbafei Mar 17 '11 at 22:49
  • This seems to be more a criticism of scripting languages in general. Haskell types work like Python's (you don't have to declare types), and it figures out what types are at compile-time (basically everything is generic unless you say otherwise). Even if Python made you declare types like C, you still wouldn't know if they were right until you try to run it. – Brendan Long Jul 23 '11 at 23:35
  • 2
    If a project's testing is so poor that `int foo = 4; Console.Write(foo.Length)` could make it into release versions if the compiler allowed it, then I **guarantee** that the project's released versions contain many many more bugs, whether or not it was written in a statically typed language. – Ben Jul 24 '11 at 06:21
  • 4
    @Ben: That was a trivial example. What if the declaration was in one module and the use was in another, and this usage is a corner case that's only accessed under certain circumstances by one user? But that one user happens to be one of your biggest clients, and this functionality is critical to their workflow, and if you don't fix it your program will fail UAT? (Purely hypothetical, but based on plenty of real experience.) There's a reason why people don't tend to write large, serious programs in dynamic languages. Without a compiler and a static type system, they grow unmanageable quickly. – Mason Wheeler Jul 25 '11 at 22:29
  • @Mason Wheeler: There will always be bugs that no static analysis can catch. This is true in languages with very strong static type systems, such as Haskell and Mercury, and it's even more true in commonly used statically languages such as Java and C# that have somewhat weaker type systems. If you write serious code that needs to have serious assurance of reliability, you **must** test it. If your testing is not good enough to find the subset of bugs that a type-checking compiler would find, it is not good enough to give very good assurances that there aren't other kinds of bugs either. – Ben Jul 26 '11 at 01:55
  • I will buy the argument that dynamic typing makes it take a bit more effort to find some bugs (although you could also argue that it's easier to debug in languages where you have more flexibility, so it's not necessarily true). But in practice projects written in dynamic languages are not more buggy than ones written in static languages. Poorly tested projects have many bugs whether the language is dynamically or statically typed. – Ben Jul 26 '11 at 02:05
  • -1 runtime errors are a reality whether or not your language is statically-typed or dynamically-typed. The compiler itself only checks syntactic errors, for everything else there's unit testing. I would trade polymorphism, object boxing, OOP relationship abuse, and other related boilerplate (ie used to make square pegs fit in round holes) for duck typing any day. – Evan Plaice May 02 '12 at 14:28
  • 3
    False, Evan. Compilers don't just check for syntactic errors; they'll also detect if you're accessing a member that doesn't exist (for example, if you mistyped the name of a property) or if you're attempting operations on a value that are not supported by the type (like trying to call something that's not a function). There's a huge class of errors that will never become runtime errors in statically-typed languages because the code won't compile. Don't deny this fact and downvote; as I said, it's arguable whether the reduced safety is worth the added power; some prefer it that way. – Jacob May 02 '12 at 16:44
  • @Brendan Long: I do not think your statement is correct: You cannot have type errors at runtime in Haskell. Either the compiler can figure out the type of an expression, or it can't. In the former case you will not have a runtime type error. In Python you can have type errors at runtime. Or did I understand it wrong? – Giorgio Jun 27 '12 at 19:01
  • 1
    @Giorgio That's exactly my point. In compiled languages (like Haskell) you can get type errors at compile time, but scripting languages (like Python) don't have a "compile time" so you can only get type errors at runtime. – Brendan Long Jun 27 '12 at 19:11
  • But if you could declare variable types or function signatures you could also perform some static type checking I guess. – Giorgio Jun 27 '12 at 19:34
  • If dynamic typing was such a hugely problematic feature, people would stop implementing it in scripting languages. The tradeoff is performance. That is all. Everything else you hear is abject cowardice on the part of devs who've never tried it a different way or who simply can't imagine what it means to actually pay attention to the flow of data through your app. – Erik Reppen Nov 29 '12 at 06:35
  • @ErikReppen, performance isn't the only tradeoff. Having developed with Python, I know firsthand that development aids such as refactoring tools and code autocompletion are hampered because of the lack of static typing, and you also lack build-time type checking. Nobody's saying that dynamic typing is "hugely problematic." There are just language tradeoffs. – Jacob Nov 29 '12 at 23:53
  • I'd kill to have decent .Net-level intellisense in PyDev. Unfortunately, 99% of the time, PyDev doesn't know what type it's dealing with (and even if it does, what properties/methods that type may have are impossible to determine) which means I spend an inrdinate amount of time remembering/typing names ala `customer.addresses.objects.`. And @ErikReppen Smooth argument - people who disagree with you must be cowards – Basic May 29 '13 at 14:50
  • @Basic Fair enough. I was grumpy at our codebase at the time. But the problem, IMO, is the way people think they're supposed to write code. I don't have your problem when I make the switch to static and I don't typically run into a lot of type issues. People can and do write complex large-scale web apps with dynamic languages and they don't have to rethink the way they write code to do the same in static languages. If static types protect you from anything they protect from learning how not to write code that makes you paranoid about your data being touched by 10,000 different sets of hands. – Erik Reppen May 29 '13 at 19:20
27

I think the object-oriented parts of Python feel kind of "bolted on". The whole need to explicitly pass "self" to every method is a symptom that it's OOP component wasn't expressly planned, you could say; it also shows Python's sometimes warty scoping rules that were criticized in another answer.

Edit:

When I say Python's object-oriented parts feel "bolted on", I mean that at times, the OOP side feels rather inconsistent. Take Ruby, for example: In Ruby, everything is an object, and you call a method using the familiar obj.method syntax (with the exception of overloaded operators, of course); in Python, everything is an object, too, but some methods you call as a function; i.e., you overload __len__ to return a length, but call it using len(obj) instead of the more familiar (and consistent) obj.length common in other languages. I know there are reasons behind this design decision, but I don't like them.

Plus, Python's OOP model lacks any sort of data protection, i.e., there aren't private, protected, and public members; you can mimic them using _ and __ in front of methods, but it's kind of ugly. Similarly, Python doesn't quite get the message-passing aspect of OOP right, either.

mipadi
  • 7,493
  • 36
  • 35
  • 17
    The self parameter is merely making [explicit](http://stackoverflow.com/questions/1984104/python-how-to-avoid-explicit-self/1984121#1984121) what other languages leave implicit. Those languages clearly have a "self" parameter. –  Oct 29 '10 at 06:08
  • 13
    @Roger Pate: Yes, but that explicit need for "self" is kind of annoying (and, I would argue, a leaky abstraction). It also didn't come about as a deliberate design decision, but due to Python's "weird" scoping rules. I can't find the article quickly, but there's a email posting from Guido van Rossum that explains nicely why the "self" parameter is required. – mipadi Oct 29 '10 at 12:54
  • @mipadi: It's less leaky than you might think; in some ways it's more consistent. A few extreme examples of that in the previous comment's link. Compare to the attitude in C++ that free functions are extension methods (I can search for the blog post from a prominent programmer about that, if you like) and how extension methods (as a formal feature) in some other languages have a fixed first parameter of "this". –  Oct 29 '10 at 13:08
  • 2
    @Roger Pate: In object-oriented languages, passing the target as the first parameter could still be considered an implementation detail. My point, though, isn't whether it's a good idea or not; the point is that in Python, it's *not* due to a conscious design decision, but rather to work around warts in the scoping system. – mipadi Oct 29 '10 at 14:08
  • @mipadi: This question is asking about drawbacks, if your point isn't that it's a bad idea, what is the purpose of this answer? Perhaps that's what I was feeling from your answer initially (and why I downvoted): you aren't justifying why this is a bad idea because you apparently never intended it that way? –  Oct 29 '10 at 14:11
  • 2
    @Roger Pate: I expressly said in my answer that the need to pass `self` as the first parameter was a *symptom* that Python's OOP side wasn't well-planned, and that it was due to Python's somewhat-broken scoping rules. (For the record, I *don't* think explicitly passing `self` is a good idea, but that's not the point.) I also elaborated in my answer that it's use is not a design decision, but due to Python's scoping rules. Not sure how I could be more clear. – mipadi Oct 29 '10 at 14:16
  • 3
    @mipadi: The update has better reasoning (so I'll remove the downvote), but if you view len as an *operator* which you overload, it's more OO in Python. Would love to see an example or reasoning on how Python gets message-passing wrong. –  Oct 29 '10 at 14:23
  • 1
    I believe http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html is the article that is being referred to. The issue essentially is that without variable decelerations its impossible to know where a value should be stored on assignment. So it is certainly true that this was produced by the design of the rest of the language. I don't see that as a bad thing, simply the fact that language design has trade offs. (Although in this case I think the explicitness is a gain not a loss) – Winston Ewert Oct 29 '10 at 15:50
  • 8
    Explicit self is an outgrowth of the fact that methods are just functions (and, as Winston noted, implicit local variable declarations). You're free to not *like* that design decision, but calling OOP "bolted on" in a language where *everything* is accessible as an object at runtime is silly. – ncoghlan Jul 13 '11 at 03:22
  • 1
    In Python, everything is an object. `object` is an object. `type` is an object. When you declare a class, that class is itself an object, and is an instance of a class! I can't think of a language with a more complete "everything is an object" world view. – Ben Jul 24 '11 at 06:31
  • @Ben: Well, there is, for example, Ruby, in which everything is not only an object, but, unlike Python, the syntax for invoking methods is consistent. – mipadi Sep 22 '11 at 17:15
  • 1
    @mipadi: everything except functions.... Which brings about the necessity of procs, blocks and lambdas, which imo is Ruby's biggest wart. – limscoder Sep 09 '12 at 02:43
  • This is likely the top or close to top answer. Threading would be the only thing I'd place as a competing complaint. – Rig Sep 10 '12 at 13:10
19

Things I don't like about Python:

  1. Threading (I know its been mentioned already, but worth mentioning in every post).
  2. No support for multi-line anonymous functions (lambda can contain only one expression).
  3. Lack of a simple but powerful input reading function/class (like cin or scanf in C++ and C or Scanner in Java).
  4. All strings are not unicode by default (but fixed in Python 3).
MAK
  • 1,093
  • 8
  • 14
  • 5
    Regarding (2), I think this is offset by the possibility to have nested functions. – Konrad Rudolph Dec 26 '10 at 12:13
  • 3
    @KonradRudolph My main qualm with nested functions instead of multi-line lambdas is the reading order gets swapped. – CookieOfFortune Sep 08 '12 at 15:36
  • Regarding (3), what about input() (called raw_input in python 2), and sys.stdin? – wkschwartz Sep 08 '12 at 16:09
  • @CookieOfFortune: OTOH, if you make the inline lambda a full-blown function, it can be unit-tested and reused elsewhere. If you need complicated lambdas, they may end up biting you later. – rbanffy Sep 08 '12 at 16:34
  • @rbanffy Sure, but it would just be nice to have the option of a middle ground. – CookieOfFortune Sep 08 '12 at 17:48
  • 4) unicode seems so much easier in Python than every other language I've worked with, which languages offer unicode by default, and doesn't it get in the way when most of your strings are simple byte arrays anyway? Isn't it easier to have to explicitly use unicode vs having to explicitly use byte arrays? – limscoder Sep 09 '12 at 02:50
  • 2
    @wkschwartz: `raw_input` and 'sys.stdin' are pretty barebones. They don't support getting formatted input (e.g. something like "%d:%d:%d" % (hour, minute, sec) to read in time). So far Python does not have anything approaching the functionality of scanf(in C) or Scanner(Java). – MAK Sep 09 '12 at 04:47
  • 2
    @limscoder: All strings are unicode by default in Java. I don't see a good reason to have separate str and unicode classes. IMHO, strings and arrays of bytes should _not_ be represented by the same abstraction. A string class should be for storing and manipulating text - whose internal representation we don't really care about. We should not want to do things like truncate/replace/delete/insert at a specific byte within a string - we want to do this at a specific _character_. Its easy to forget the distinction and have your code blow up when fed non-english input. – MAK Sep 09 '12 at 05:07
  • 1
    @limscoder: if you want to see easy unicode, try Tcl. I had to switch from Tcl to Python a few years back, and boy was I surprised at how primitive python's unicode support is in comparrison. It's truly invisible in Tcl, and a major pain in python. – Bryan Oakley Sep 10 '12 at 11:00
  • for the things your answer states it is too short to the point of being misleading while not being entirely incorrect. C++/Java are better than Python for string parsing? wtf. – jfs Jun 02 '13 at 19:23
  • @J.F.Sebastian: I think my answer states clearly what is lacking here. Python does not provide something as simple as scanf for reading formatted text. Where exactly is this misleading? – MAK Jun 02 '13 at 21:43
  • Python is not C. You could use [string manipulations](http://ideone.com/p2Q3kU), [regular expressions](http://docs.python.org/2/library/re.html#simulating-scanf), [specialized parsers](http://docs.python.org/2/library/datetime#strftime-and-strptime-behavior) out of the box. There are several modules that provide scanf-like functionality but none are popular. So technically you're correct: there is no scanf in stdlib but it is misleading to suggest that it makes the input handling in Python more complex or less powerful compared to the alternatives. – jfs Jun 02 '13 at 23:25
  • @J.F.Sebastian: It certainly isn't less powerful, but I disagree that it isn't more complex. My point is, having something like Scanner or scanf would make life simpler when reading simple formatted input - not saying it is impossible or even too hard to do this in Python right now. – MAK Jun 03 '13 at 09:46
18

Default arguments with mutable data types.

def foo(a, L = []):
    L.append(a)
    print L

>>> foo(1)
[1]
>>> foo(2)
[1, 2]

It's usually the result of some subtle bugs. I think it would be better if it created a new list object whenever a default argument was required (rather than creating a single object to use for every function call).

Edit: It's not a huge problem, but when something needs to be referred in the docs, it commonly means it's a problem. This shouldn't be required.

def foo(a, L = None):
    if L is None:
        L = []
    ...

Especially when that should have been the default. It's just a strange behavior that doesn't match what you would expect and isn't useful for a large number of circumstances.

jsternberg
  • 1,531
  • 11
  • 15
  • I see lots of complaints about this, but why does people insist having an empty list (that the function modifies) as a default argument? Is this really such a big problem? I.e., is this a *real* problem? – Martin Vilcans Jul 25 '11 at 21:22
  • 8
    It violates the principle of least surprise. One wouldn't expect a function's parameters to survive across calls. – aib Sep 09 '12 at 00:19
  • It's a consequence of it being a scripting language. You will only get stumped by this bug ONCE, and never again. Figuring this bug out for yourself really gives you a kick in the butt to remind you that yes, this is still a scripting language. And that's only because the language is that good in hiding the scripting aspect (assuming you use it correctly). – Zoran Pavlovic Jan 07 '13 at 06:32
  • @ZoranPavlovic out of curiosity, why is this a consequence of it being a scripting language? It seems to be a problem with when the data is bound and because lists are mutable (which are two things that are normally good, but end up being bad when combined together). The same issue could happen in a non-scripting language if you bound the data at the time of function creation rather than creating a new list each time the function was called. – jsternberg Jan 07 '13 at 17:19
  • @aib: I don't think so -- the parameter here, like every other Python object -- is a pointer to an object. In this case, the object is a mutable one, and the variable is bound when the function is declared. The parameter does "survive across calls," but what survives is the reference to a mutable object. – Patrick Collins Dec 30 '13 at 23:10
  • @PatrickCollins: I'm aware it's the reference that survives, but the important thing is the end result. // PHP has a similar problem with reference `foreach`es, also resulting in subtle bugs. – aib Dec 31 '13 at 11:24
14

Some of Python's features that make it so flexible as a development language are also seen as major drawbacks by those used to the "whole program" static analysis conducted by the compilation and linking process in languages such as C++ and Java.

  • Implicit declaration of local variables

Local variables are declared using the ordinary assignment statement. This means that variable bindings in any other scope require explicit annotation to be picked up by the compiler (global and nonlocal declarations for outer scopes, attribute access notation for instance scopes). This massively reduces the amount of boilerplate needed when programming, but means that third party static analysis tools (such as pyflakes) are needed to perform checks that are handled by the compiler in languages that require explicit variable declarations.

  • "Monkey patching" is supported

The contents of modules, class objects and even the builtin namespace can be modified at runtime. This is hugely powerful, allowing many extremely useful techniques. However, this flexibility means that Python does not offer some features common to statically typed OO languages. Most notably, the "self" parameter to instance methods is explicit rather than implicit (since "methods" don't have to be defined inside a class, they can be added later by modifying the class, meaning that it isn't particularly practical to pass the instance reference implicitly) and attribute access controls can't readily be enforced based on whether or not code is "inside" or "outside" the class (as that distinction only exists while the class definition is being executed).

  • Far from the metal

This is also true of many other high level languages, but Python tends to abstract away most hardware details. Systems programming languages like C and C++ are still far better suited to handling direct hardware access (however, Python will quite happily talk to those either via CPython extension modules or, more portably, via the ctypes library).

ncoghlan
  • 3,619
  • 1
  • 18
  • 13
12
  1. Using indentation for code blocks instead of {} / begin-end, whatever.
  2. Every newer modern language has proper lexical scoping, but not Python (see below).
  3. Chaotic docs (compare with Perl5 documentation, which is superb).
  4. Strait-jacket (there's only one way to do it).

Example for broken scoping; transcript from interpreter session:

>>> x=0
>>> def f():
...     x+=3
...     print x
... 
>>> f()
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 2, in f
UnboundLocalError: local variable 'x' referenced before assignment

global and nonlocal keywords have been introduced to patch this design stupidity.

zvrba
  • 3,470
  • 2
  • 23
  • 22
  • 2
    regarding the scoping, it might worth it for the curious to look at http://www.python.org/dev/peps/pep-3104/ to understand the reasoning of the current method. – Winston Ewert Oct 30 '10 at 01:13
  • Agree with +1. So, +1. – Jas Nov 11 '10 at 13:12
  • +1, except that the strait-jacket isn't as tight as it used to be. – Larry Coleman Nov 11 '10 at 15:58
  • 34
    Having one way to do it is an advantage. When you read someone else's code you don't have decipher ever single statement. Once the idioms are hardwired in your brain, you should have instant recognition. – rox0r Dec 18 '10 at 07:21
  • 9
    Completely agree with @rox0r. The "straight-jacket" prevents all sorts of syntax wars. – keithjgrant Jan 13 '11 at 22:03
  • 8
    To be honest, I very rarely need the `global` or `nonlocal` keywords in Python. So rarely that I forget this issue exists and have to re-google it the few times it's come up, despite the fact that I write Python code every day at work. To me, code that needs to modify global variables (or worse, outer non-global variables) is a code smell. There's usually (not always) a better way. – Ben Jul 24 '11 at 06:26
  • -1: #1: IMO, that's an advantage. #2: I don't see a problem with this; like Ben, I think there are almost always better ways. #3: Python docs aren't perfect, but I can find what I need. #4: That has never really been true, but the Python philosophy does suggest that there should be one *best* way to do things; IMO, this is better than having a dozen different ways to do something and then feeling lost when you look at someone else's code in that language. – GreenMatt Jul 25 '11 at 18:54
  • #4:Not true. If anything, python gives you a multitude of ways to solve a lot of problems, at any level, be it low or high. It may be a scripting language, but that doesn't mean it in any way restricts you. As for #2: I think you need to learn OOP, because if you ever have to use the global keyword, you're not programming right. Using global is a very bad code-smell as Ben above mentions. – Zoran Pavlovic Jan 07 '13 at 06:40
  • @GreemMatt, #1 is absolutely a disadvantage! It becomes silly to replace Perl with Python to do quick and dirty shell tasks. You can't have multiple commands in one line in Python. Really annoying and limiting. – Apprentice Queue Sep 24 '13 at 03:16
11

I find python's combination of object-oriented this.method() and procedural/functional method(this) syntax very unsettling:

x = [0, 1, 2, 3, 4]
x.count(1)
len(x)
any(x)
x.reverse()
reversed(x)
x.sort()
sorted(x)

This is particularly bad because a large number of the functions (rather than methods) are just dumped into the global namespace: methods relating to lists, strings, numbers, constructors, metaprogramming, all mixed up in one big alphabetically-sorted list.

At the very least, functional languages like F# have all the functions properly namespaced in modules:

List.map(x)
List.reversed(x)
List.any(x)

So they aren't all together. Furthermore, this is a standard followed throughout the library, so at least it's consistent.

I understand the reasons for doing the function vs method thing, but i still think it's a bad idea to mix them up like this. I would be much happier if the method-syntax was followed, at least for the common operations:

x.count(1)
x.len()
x.any()
x.reverse()
x.reversed()
x.sort()
x.sorted()

Whether the methods are mutating or not, having them as methods on the object has several advantages:

  • Single place to look up the "common" operations on a data-type: other libraries/etc. may have other fancy things they can do to the datatypes but the "default" operations are all in the object's methods.
  • No need to keep repeating the Module when calling Module.method(x). Taking the functional List example above, why do i have to keep saying List over and over? It should know that it's a List and I don't want to call the Navigation.map() function on it! Using the x.map() syntax keeps it DRY and still unambiguous.

And of course it has advantages over the put-everything-in-global-namespace way of doing it. It's not that the current way is incapable of getting things done. It's even pretty terse (len(lst)), since nothing is namespaced! I understand the advantages in using functions (default behavior, etc.) over methods, but I still don't like it.

It's just messy. And in big projects, messiness is your worst enemy.

Haoyi
  • 1
  • 1
  • 3
  • 1
    yeah... I really miss LINQ style (I'm sure LINQ isn't the first to implement it, but I'm most familiar with it) list handling. – CookieOfFortune Sep 08 '12 at 15:38
  • 1
    Don't think of len(x) as a method. "len" is a function. Python has functions *and* methods and I see nothing wrong with that approach. Lack of proper functions is, usually, the source of a lot of needless typing. – rbanffy Sep 08 '12 at 16:42
  • I know `len()` is a function, and what the advantages are. I also stated why I think it's a bad idea, why I think the **global** functions are a particularly bad idea, and why i think methods provide a convenient method of organizing and scoping your functionality =) – Haoyi Sep 08 '12 at 16:49
  • I don't think that 42 (or is it 43?) keywords is a 'large' number. That also includes things like `def`, `class` and other non-function calls. Compare that with 100+ in most other popular languages. Also, consider the line from `import this`: `Namespaces are one honking great idea -- let's do more of those!`. I think you might misunderstand Python namespaces ;) – Wayne Werner Sep 09 '12 at 04:12
8

Lack of homoiconicity.

Python had to wait for 3.x to add a "with" keyword. In any homoiconic language it could have trivially been added in a library.

Most other issues I've seen in the answers are of one of 3 types:

1) Things that can be fixed with tooling (e.g. pyflakes) 2) Implementation details (GIL, performance) 3) Things that can be fixed with coding standards (i.e. features people wish weren't there)

#2 isn't a problem with the language, IMO #1 and #3 aren't serious problems.

gnat
  • 21,442
  • 29
  • 112
  • 288
Jason
  • 101
  • 1
  • 1
  • 1
    `with` was available from Python 2.5 with `from __future__ import with_statement`, but I agree, I've occasionally found it unfortunate that statements like `if`/`for`/`print`/etc are "special" instead of regular functions – dbr Sep 09 '12 at 22:03
7

Python is my favourite language as it is very expressive, but still keeps you from making too many mistakes. I still have a few things that annoy me:

  • No real anonymous functions. Lambda can be used for single-statement functions, and the with statement can be used for many things where you'd use a code block in Ruby. But in some situations it makes things a bit more clumsy than they would have to be. (Far from as clumsy as it would be in Java, but still...)

  • Some confusion in the relation between modules and files. Running "python foo.py" from the command line is different from "import foo". Relative imports in Python 2.x can also cause problems. Still, Python's modules is so much better than the corresponding features of C, C++ and Ruby.

  • Explicit self. Even though I understand some of the reasons for it, and even though I use Python daily, I tend to make the mistake of forgetting it. Another issue with it is that it becomes a bit tedious to make a class out of a module. Explicit self is related to the limited scoping that others have complained about. The smallest scope in Python is the function scope. If you keep your functions small, as you should, that isn't a problem by itself and IMO often gives cleaner code.

  • Some global functions, such as len, that you'd expect to be a method (which it actually is behind the scenes).

  • Significant indentation. Not the idea itself, which I think is great, but since this is the single thing that keeps so many people from trying Python, perhaps Python would be better off with some (optional) begin/end symbols. Ignoring those people, I could totally live with an enforced size for the indentation too.

  • That it is not the built-in language of web browsers, instead of JavaScript.

Of these complaints, it's only the very first one that I care enough about that I think it should be added to the language. The other ones are rather minor, except for the last one, which would be great if it happened!

Martin Vilcans
  • 939
  • 1
  • 7
  • 8
  • +1 It makes me wonder whether to write `datetime.datetime.now()` when one project could write `datetime.now` and then mixing two projects one way of writing it rules out the other and surely this wouldn't have happened in Java which wouldn't name a module the same as a file(?) if you see how the common way seems to have the module confusing us with the file when both uses are practiced and explicit `self` I still try to understand since the calls don't have the same number of arguments as the functions. And you might thinkn that the VM python has is slow? – Niklas Rosencrantz Sep 01 '11 at 16:19
  • Regarding your problem with the explicit self keyword. Might I suggest using a good python IDE for that? I know PyDev on Eclipse auto-completes the self portion of a function signature if it detects you're writing inside a class. – Zoran Pavlovic Jan 07 '13 at 06:42
5

Python is not fully mature: the python 3.2 language at this moment in time has compatibility problems with most of the packages currently distributed (typically they are compatible with python 2.5). This is a big drawback which currently requires more development effort (find the package needed; verify compatibility; weigh choosing a not-as-good package which may be more compatible; take the best version, update it to 3.2 which could take days; then begin doing something useful).

Likely in mid-2012 this will be less of a drawback.

Note that I guess I got downvoted by a fan-boy. During a developer discussion our high level developer team reached the same conclusion though.

Maturity in one main sense means a team can use the technology and be very quickly up & running without hidden risks (including compatibility problems). 3rd party python packages and many apps do not work under 3.2 for the majority of the packages today. This creates more work of integration, testing, reimplementing the technology itself instead of solving the problem at hand == less mature technology.

Update for June 2013: Python 3 still has maturity problems. Every so often a team member will mention a package needed then say "except it is only for 2.6" (in some of these cases I've implemented a workaround via localhost socket to use the 2.6-only package with 2.6, and the rest of our tools stay with 3.2). Not even MoinMoin, the pure-python wiki, is written in Python 3.

  • 2
    I agree with you only if your definition of maturity is *not compatible with a version that is incompatible by design*. – tshepang Jul 17 '11 at 07:25
  • 3
    I agree that python's two incompatible streams is a problem (although understandable why it was done), but I don't see that as an issue of "maturity". – Winston Ewert Jul 24 '11 at 00:04
  • Maturity in one sense means a team can use the technology and be very quickly up & running without hidden risks (including compatibility problems). 3rd party python packages and many apps do not work under 3.2 for the majority of the packages today. This creates more work of integration, testing, reimplementing the technology itself instead of solving the problem at hand == less mature technology. – Jonathan Cline IEEE Jul 25 '11 at 17:35
  • Solution: Don't use Python 3.x. It's not mature. Python 2.x is. – Martin Vilcans Jul 25 '11 at 21:23
  • 2
    Then just use Python 2.x. You know... the version everybody is using. Or read the packages documentation for 2 seconds to figure out what versions it's compatible with. – jsternberg Jul 25 '11 at 22:46
  • "Python 3.0 final was released on December 3rd, 2008." It's currently July, 2011. – Jonathan Cline IEEE Jul 26 '11 at 00:30
  • Just because python 3.0 has been released for some time doesn't mean its the version you should use. Python 3.0 and 2.x are being developed at the same time. I hope that in the future we'll all be able to use python 3.0, but for now using 2.x is a good solution. – Winston Ewert Jul 26 '11 at 07:06
  • 2
    "Just because python 3.0 has been released for some time doesn't mean its the version you should use. Python 3.0 and 2.x are being developed at the same time. I hope that in the future we'll all be able to use python 3.0, but for now using 2.x is a good solution" -> That's a 500 character way of saying: It's not yet mature. – Jonathan Cline IEEE Jul 27 '11 at 02:22
  • I think it is perfectly fine that the compatibility is broken. I think many changes made in Python 3 are reasonable and makes the language more predictable in some of the cases. And str being Unicode by default in Python 3 saves me quite a lot of trouble. – nhahtdh Sep 09 '12 at 05:45
  • +1. "Sure, Python's mature; just use 2.x" would be a fine response if it weren't for the fact that "That's fixed in Python 3.x; just use 3.x" is the response for half the other answers on this page. – Andrew Janke Nov 26 '12 at 03:25
  • Cant have both, you either break compatibility or be stuck with bad design forever. – Kugel Dec 03 '12 at 08:38
  • @JonathanClineIEEE Well what would you suggest they do? Not add features for fear of breaking compatibility? Or bolt-on features in awkward ways such as not to break compatibility? Really, splitting the language into two minor divergent streams and allowing library developers to switch over at their own pace is the best solution to the problem. And it has nothing to do with "maturity". I don't think you and your "high level developer team" understand the meaning of the term maturity in this context. – Zoran Pavlovic Jan 07 '13 at 06:52
  • Don't flame me or my team for stating the truth. – Jonathan Cline IEEE May 23 '13 at 22:03
4

Python's scoping is badly broken, which makes object-oriented programming in Python very awkward.

Mason Wheeler
  • 82,151
  • 24
  • 234
  • 309
  • 8
    can you give an example? (I'm sure you are right, but I'd like an example) – Winston Ewert Oct 28 '10 at 22:36
  • 1
    @Winston: I saw a great article that explains it in a lot better detail than I can, but I can't find it now. :( The basic idea is that the weird feel of Python's OOP, stuff like having to declare the Self parameter explicitly, is because Python's scoping is really wonky. Also, it has a bunch of more obvious scope problems like not being able to access outer-scope variables from within nested functions. – Mason Wheeler Oct 28 '10 at 23:42
  • 24
    I like Python but I absolutely _despise_ having to put `self.` in front of every reference to an instance property and method. It makes it impossible to use Python to create a DSL like it is so easy to do in Ruby. – Adam Crossland Oct 29 '10 at 00:05
  • 35
    I don't find the self awkward, I like the explicitness. – Winston Ewert Oct 29 '10 at 00:48
  • 1
    To each his own, I suppose. – Adam Crossland Oct 29 '10 at 00:51
  • 9
    I don't see what the big deal about explicit self is. In C++, Java and D, people often make member variables explicit by convention anyhow, for example by prefixing them with an underscore. – dsimcha Oct 29 '10 at 01:14
  • 7
    You use self in methods different from their declaration: def foo(self) but self.foo(). I find this mixture of explicit definition but implicit behind-the-scenes stuff not too pretty. – LennyProgrammers Oct 29 '10 at 09:19
  • 1
    @Mason: "...like not being able to access outer-scope variables from within nested functions." — Not true. You can access them just fine, it's assignment that's an issue in 2.x; but, honestly, I think I've run into that problem twice in the past year. –  Oct 29 '10 at 14:17
  • 2
    To rephrase this answer: "I'd prefer it if methods were not ordinary functions, but instead had an additional implicit namespace they could access." Indeed, a valid response to this question, as the fact that methods are just functions that happen to be retrieved from class instances is a basic part of the object design. – ncoghlan Jul 13 '11 at 03:15
  • 3
    I really dislike the **implicit** self in languages like Java and C++. Especially when I'm defining binary operations like `def add(self, other)`; I find it dissatisfyingly asymmetrical to then type `return member + other.member`. But more generally, Python makes it much easier to distinguish between local variables and instance methods, without having to resort to asking a fancy IDE. – Ben Jul 24 '11 at 06:17
  • 1
    @AdamCrossland I like C# but I absolutely despise having to put 'static' in front of every reference to a non-instance property and method. Touche... – Evan Plaice May 02 '12 at 14:16
  • -1: I think this answer needs some sort of example to be useful. You say it's broken because it makes programming awkward, but awkward is subjective. Give future information-seekers an example to support your claim – Bryan Oakley Sep 10 '12 at 11:06
4

My gripes about Python:

  • Bolted-on OOP (See @mipadi's answer for elaboration on this)
  • Broken implementation of lambdas
  • Scope issues
  • No persistent collections in the standard library
  • Poor amenability to embedded DSLs
missingfaktor
  • 3,906
  • 1
  • 24
  • 31
4

Access modifiers in Python are not enforcable - makes it difficult to write well structured, modularized code.

I suppose that's part of @Mason's broken scoping - a big problem in general with this language. For code that's supposed to be readable, it seems quite difficult to figure what can and should be in scope and what a value will be at any given point in time - I'm currently thinking of moving on from the Python language because of these drawbacks.

Just because "we're all consenting adults" doesn't mean that we don't make mistakes and don't work better within a strong structure, especially when working on complex projects - indentation and meaningless underscores don't seem to be sufficient.

Vector
  • 3,180
  • 3
  • 22
  • 25
  • So lack of access controls is bad... but explicit scoping of variable writes to any non-local namespace is also bad? – ncoghlan Jul 13 '11 at 03:25
  • @ncoghlan: 1 - that feature is standard in many modern languages, depending on how you configure your project . 2 -It's under the programmer's control. 3 - not sure what's so great about that - you can easily control your scope with a few project settings in most compiled languages/IDE's. If 'we're all consenting adults', we should be able to make our own decisions and adjust scope according to our particular comfort level. – Vector Jul 13 '11 at 13:21
  • 2
    The thing is that people asking for "enforced access controls" are asking us to take out one of the very things that makes Python such a great glue language: it's deliberately *hard* for developers to control how their code is later used. How much of the boilerplate in C++ and Java patterns is there solely to work around the enforced access controls? I can definitely understand people choosing not to use Python for those reasons, but static enforcement is never going to be a substitute for rigorous testing. – ncoghlan Jul 14 '11 at 05:02
  • 1
    @ncoghlan - to me the great things about Python are elegance of syntax and succintness - expressiveness. And as i said, scoping has less to do with programmers messing with things they shouldn't than it does with code structure and organization - so the concept of 'consenting adults' is moot. I work on complex projects, not simple utilities and scripts - the code must be carefully modularized and structured - access modifiers are one of the most important ways of ensuring that. – Vector Jul 14 '11 at 06:56
  • 1
    And code review, training and coupling analysis are others. To me, enforced access controls fall into the same bucket as static typing: they do help in providing some additional confidence in correctness (but not enough to avoid the need for extensive testing), but at a high cost in development productivity. (At a practical level, class attribute access controls also don't fit with Python's object model where methods are just ordinary functions retrieved from classes. The "inside/outside" boundary for classes doesn't really exist, so it can't be enforced) – ncoghlan Jul 14 '11 at 07:20
  • Actually, "Python supports monkey patching" is the core principle lying behind both of these objections. I think I'll add that as an answer... – ncoghlan Jul 14 '11 at 07:53
3

Multiple dispatch does not integrate well with the established single-dispatch type system and is not very performant.

Dynamic loading is a massive problem on parallel file systems where POSIX-like semantics lead to catastrophic slow-downs for metadata-intensive operations. I have colleagues that have burned a quarter million core-hours just getting Python (with numpy, mpi4py, petsc4py, and other extension modules) loaded on 65k cores. (The simulation delivered a significant new science results, so it was worth it, but it is a problem when more than a barrel of oil is burned to load Python once.) Inability to link statically has forced us to go to great contortions to get reasonable load times at scale, including patching libc-rtld to make dlopen perform collective file system access.

Jed
  • 141
  • 5
  • Wow, seems highly technical, do you have any reference material, examples, blog posts or articles on the subject ? I wonder if I might be exposed to such cases in a near future. – vincent Sep 08 '12 at 20:00
  • Aron gave a [talk at SciPy 2012](http://www.youtube.com/watch?v=BpuykTOy4a0). The `dlopen` stuff is in our [collfs](https://github.com/ahmadia/collfs) library. That repository also contains additional zipimport tricks inspired by Asher Langton's path caching. We are working on better distribution and a paper. – Jed Sep 08 '12 at 20:31
3
  • quite a bunch of very mainstream 3rd party libraries and software that are widely used, are quite not pythonic. A few examples : soaplib, openerp, reportlab. Critique is out-of-scope, it's there, it's widely used, but it makes the python culture confusing ( it hurts the motto that says " There should be one-- and preferably only one --obvious way to do it "). Known pythonic successes ( such as django or trac ) seem to be the exception.
  • the potentially unlimited depth of abstraction of instance, class, metaclass is conceptually beautiful and unique. But to master it you have to deeply know the interpreter ( in which order python code is interpreted, etc. ). It's not widely known and used ( or used correctly ), while similar black magic such as C# generics, that is conceptually more convoluted ( IMHO ) seems more widely known and used, proportionally.
  • to get a good grasp of memory and threading model, you have to be quite experienced with python, because there's no comprehensive spec. You just know what works, maybe because you read the interpreter's sources or experienced quirks and discovered how to fix them. For instance, there are only strong or weak references, not the soft and phantom refs of java. Java has a thread for garbage collection while there is no formal answer about when garbage collection happens in python ; you can just observe that garbage collection doesn't happen if no python code is executed, and conclude it's probably happening sometimes when trying to allocate memory. Can be tricky when you don't know why a locked resource wasn't released ( my experience about that was mod_python in freeswitch ).

Anyhow, python is my main language for 4 years now. Being fanboys, elitists or monomaniacs is not a part of the python culture.

vincent
  • 101
  • 3
  • +1. Spec for memory and threading model is right on. But FWIW, the Java garbage collector being on a thread (and most everything else about the GC) is not an aspect of the Java language or VM specifications per se, but is a matter of a particular JVM's implementation. However, the main Sun/Oracle JVM is extensively documented wrt GC behavior and configurability, to the extent that there are whole books published on JVM tuning. In theory one could document CPython in the same way, regardless of language spec. – Andrew Janke Nov 26 '12 at 03:44
3
  1. The performance is not good, but is improving with pypy,
  2. The GIL prevents the use of threading to speed up code, (although this is usually a premature optimization),
  3. It's only useful for application programming,

But it has some great redeeming features:

  1. It's perfect for RAD,
  2. It's easy to interface with C (and for C to embed a python interpreter),
  3. It's very readable,
  4. It's easy to learn,
  5. It's well documented,
  6. Batteries really are included, it's standard library is huge and pypi contains modules for practically everything,
  7. It has a healthy community.
dan_waterworth
  • 7,287
  • 2
  • 34
  • 45
  • What inspired to mention the advantages? The question for the problems. Anyways, what you mean it's useful only for application programming? What other programming is there? What specifically is it not good for? – tshepang Dec 30 '10 at 13:27
  • 5
    I listed the advantages because I think they outweigh the cons. Have you ever tried to implement a linux kernel module in python. – dan_waterworth Dec 30 '10 at 16:34
3

I do favor python and the first disadvantage that comes to my mind is when commenting out a statement like if myTest(): then you must change the indentation of the whole executed block which you wouldn't have to do with C or Java. In fact in python instead of commenting out an if-clause instead I've started to comment it out this way: `if True:#myTest() so I won't also have to change the following code block. Since Java and C don't rely on indentation it makes commenting out statements easier with C and Java.

Niklas Rosencrantz
  • 8,008
  • 17
  • 56
  • 95
  • 1
    You would seriously edit C or Java code to change the block level of some code without changing its indentation? – Ben Jul 24 '11 at 06:35
  • 4
    @Ben Temporarily, yes... – alternative Jul 24 '11 at 14:36
  • 1
    @ben same here. – Christopher Mahan Jul 25 '11 at 18:11
  • 2
    I use the trick of changing `if something()` to `if False and something()`. Another trick is to "comment out" using a multi-line string. – Martin Vilcans Jul 25 '11 at 22:23
  • 1
    @Martin Of Course! if False... – Christopher Mahan Jul 25 '11 at 23:40
  • 1
    Ok, I take your point. It's not something that has been problematic for me very often though. I find such slight inconveniences well outweighed by the lack of problems caused by the inevitable bad indentation that creeps into code written in languages where the compiler uses brace matching to read the code. Humans tend to find the spatial layout created by indentation easier to understand than scanning for matching braces (it's why we indent C code), so it just seems more logical to have the compiler use indentation too. – Ben Jul 26 '11 at 02:01
  • I was going to accept some code I tested so therefore I changed `if condition()` to `if True:#conditation()` and I learnt some statements I wrote where never reached and all this because of intendation that otherwise would've been a syntax error. I appeared to have intented too much and therefore some statements were never reached and just as I moved a block one space to the left it just worked again. So it might not always be an advantage to depend on indendation. Now I run the tool `reindent.py`regularly and an editor called drPython can move entire blocks which also helps to format code. – Niklas Rosencrantz Sep 01 '11 at 16:08
  • @NickRosencrantz You really should be using an IDE for that. A simple press of the tab/alt-tab keys will indent/deindent any code block for you. Not to mention that it automatically aligns for you to current depth, or one depth deeper if you just created an if/method/function. PyDev on Eclipse is my recommendation. – Zoran Pavlovic Jan 07 '13 at 06:59
2
  • Strange OOP:
    • len(s) through __len__(self) and other "special methods"
    • extra special methods which could be derived from other special methods (__add__ and __iadd__ for + and +=)
    • self as first method parameter
    • you can forget to call base class constructor
    • no access modifiers (private, protected ...)
  • no constant definitions
  • no immutability for custom types
  • GIL
  • poor performance which leads to a mix of Python and C and troubles with builds (looking for C libs, platform dependencies ...)
  • bad documentation, especially in third party libs
  • incompatibility between Python 2.x and 3.x
  • poor code analysis tools (compared to what is offered for statically typed languages such as Java or C#)
deamon
  • 876
  • 5
  • 14
  • 5
    Personally I think that incompatibility between between 2.x and 3.x is one of Python’s biggest advantages. Sure, it *also* is a disadvantage. But the audacity of the developers to break backwards compatibility also means that they didn’t have to carry cruft around endlessly. More languages need such an overhaul. – Konrad Rudolph Sep 10 '12 at 13:39
0

"Immutability" is not exactly it's strong point. AFAIK numbers, tuples and strings are immutable, everything else (i.e. objects) is mutable. Compare that to functional languages like Erlang or Haskell where everything is immutable (by default, at least).

However, Immutability really really shines with concurrency*, which is also not Python's strong point, so at least it's consequent.

(*= For the nitpickers: I mean concurrency which is at least partially parallel. I guess Python is ok with "single-threaded" concurrency, in which immutability is not as important. (Yes, FP-lovers, I know that immutability is great even without concurrency.))

Kosta
  • 181
  • 1
  • 4
0

I'd love to have explicitly parallel constructs. More often than not, when I write a list comprehension like

[ f(x) for x in lots_of_sx ]

I don't care the order in which the elements will be processed. Sometimes, I don't even care in which order they are returned.

Even if CPython can't do it well when my f is pure Python, behavior like this could be defined for other implementations to use.

rbanffy
  • 353
  • 2
  • 8
  • //spawn bunch of threads //pass Queue que to all threads que.extend([x for x in lots_of_sx]) que.wait() # Wait for all lots_of_sx to be processed by threads. – Zoran Pavlovic Jan 07 '13 at 07:02
0

Python has no tail-call optimization, mostly for philosophical reasons. This means that tail-recursing on large structures can cost O(n) memory (because of the unnecessary stack that is kept) and will require you to rewrite the recursion as a loop to get O(1) memory.

Walter
  • 16,158
  • 8
  • 58
  • 95
a3nm
  • 101
  • 2