147
votes

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)

13
  • 50
    I think that this is a helpful subjective question, and it would be a shame to close it. Oct 29, 2010 at 0:09
  • 25
    There seems to be a python-fanboy here who just downvotes all anti-python answers.
    – zvrba
    Oct 29, 2010 at 9:54
  • 2
    @TMN: That's still treating the whitespace as tokens, just not returning them — and it's exactly what Python's grammar does too.
    – Roger Pate
    Oct 29, 2010 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, 2010 at 20:48
  • 8
    @zvrba: Downvotes still mean "not useful", just as always.
    – Roger Pate
    Oct 30, 2010 at 2:32

24 Answers 24

109
votes

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.

16
  • 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++. Oct 29, 2010 at 6:14
  • 17
    About 5 - just use pyflakes. It's written to catch exactly those errors. Jul 12, 2011 at 9: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, 2011 at 3:07
  • 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. Jul 23, 2011 at 1:53
  • 5
    How can distance from the metal be an argument? Did Python ever purport itself to be a systems language? Sep 9, 2012 at 0:01
66
votes

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]
18
  • 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, 2011 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. Jul 19, 2011 at 0: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. Jul 23, 2011 at 23:58
  • 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 … Jul 24, 2011 at 13:48
  • 3
    +1 For adding better 'functional-like' programming abilities. May 2, 2012 at 14:33
44
votes

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.

7
  • 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, 2010 at 0:48
  • 3
    Threading is not well supported? The threading libraries have been in there since before 2.1.
    – rox0r
    Dec 18, 2010 at 7: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, 2010 at 23:15
  • 2
    The documentation is good if you can manage to find it. Googling Java classes is much easier than Python. Jul 23, 2011 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 8, 2012 at 13:05
28
votes

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

21
  • 5
    This is correct, though there are tools like PyChecker which can check for errors a compiler in languages like C/Java would do. Oct 28, 2010 at 23:42
  • 24
    Dynamic typing is a conscious design decision, not a drawback. Nov 11, 2010 at 12:18
  • 14
    Its the same as saying Java's weakness is lack of dynamic typing.
    – MAK
    Nov 11, 2010 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, 2010 at 16:27
  • 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, 2010 at 16:29
27
votes

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.

13
  • 17
    The self parameter is merely making explicit what other languages leave implicit. Those languages clearly have a "self" parameter.
    – Roger Pate
    Oct 29, 2010 at 6: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, 2010 at 12:54
  • 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, 2010 at 14:08
  • 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.
    – Roger Pate
    Oct 29, 2010 at 14:23
  • 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, 2011 at 3:22
19
votes

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).
13
  • 5
    Regarding (2), I think this is offset by the possibility to have nested functions. Dec 26, 2010 at 12:13
  • 3
    @KonradRudolph My main qualm with nested functions instead of multi-line lambdas is the reading order gets swapped. Sep 8, 2012 at 15:36
  • 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 9, 2012 at 4: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 9, 2012 at 5: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. Sep 10, 2012 at 11:00
18
votes

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.

6
  • 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? Jul 25, 2011 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 9, 2012 at 0: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). Jan 7, 2013 at 6: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 7, 2013 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. Dec 30, 2013 at 23:10
14
votes

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).

12
votes
  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.

9
  • 2
    regarding the scoping, it might worth it for the curious to look at python.org/dev/peps/pep-3104 to understand the reasoning of the current method. Oct 30, 2010 at 1:13
  • Agree with +1. So, +1.
    – Jas
    Nov 11, 2010 at 13:12
  • 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, 2010 at 7:21
  • 9
    Completely agree with @rox0r. The "straight-jacket" prevents all sorts of syntax wars. Jan 13, 2011 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, 2011 at 6:26
11
votes

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.

4
  • 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. Sep 8, 2012 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 8, 2012 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 8, 2012 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 ;) Sep 9, 2012 at 4:12
8
votes

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.

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 9, 2012 at 22:03
7
votes

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!

2
  • +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? Sep 1, 2011 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. Jan 7, 2013 at 6:42
5
votes

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.

13
  • 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, 2011 at 7: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". Jul 24, 2011 at 0: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. Jul 25, 2011 at 17:35
  • 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, 2011 at 22:46
  • 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. Jul 27, 2011 at 2:22
4
votes

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

12
  • 8
    can you give an example? (I'm sure you are right, but I'd like an example) Oct 28, 2010 at 22:36
  • 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. Oct 29, 2010 at 0:05
  • 35
    I don't find the self awkward, I like the explicitness. Oct 29, 2010 at 0:48
  • 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, 2010 at 1: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. Oct 29, 2010 at 9:19
4
votes

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
4
  • Why the downvote? Dec 26, 2010 at 13:32
  • I'm not the downvoter, but can you explain why you think the OO is bolted on? Python has always had OO, it's a core part of the language.
    – Daenyth
    Jul 15, 2011 at 13:58
  • See @mipadi's answer. Jul 15, 2011 at 15:40
  • With link to @mipadi's answer
    – JB.
    Sep 8, 2012 at 12:48
4
votes

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.

6
  • So lack of access controls is bad... but explicit scoping of variable writes to any non-local namespace is also bad?
    – ncoghlan
    Jul 13, 2011 at 3: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, 2011 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, 2011 at 5: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, 2011 at 6: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, 2011 at 7:20
3
votes
  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.
2
  • 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, 2010 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. Dec 30, 2010 at 16:34
3
votes

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.

8
  • 1
    You would seriously edit C or Java code to change the block level of some code without changing its indentation?
    – Ben
    Jul 24, 2011 at 6:35
  • 4
    @Ben Temporarily, yes... Jul 24, 2011 at 14:36
  • 1
    @ben same here. Jul 25, 2011 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. Jul 25, 2011 at 22:23
  • 1
    @Martin Of Course! if False... Jul 25, 2011 at 23:40
3
votes

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.

2
  • 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 8, 2012 at 20:00
  • Aron gave a talk at SciPy 2012. The dlopen stuff is in our 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 8, 2012 at 20:31
3
votes
  • 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.

1
  • +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. Nov 26, 2012 at 3:44
2
votes
  • 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#)
1
  • 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. Sep 10, 2012 at 13:39
0
votes

"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.))

0
votes

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.

1
  • //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. Jan 7, 2013 at 7:02
0
votes

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.