
What are the drawbacks of Python? - denzil_correa
http://programmers.stackexchange.com/questions/15468/what-are-the-drawbacks-of-python
======
cdavid
Quite a few poor and superficial answers in that link. The usual argument that
dynamic typing does not scale for large projects is largely unfounded. There
are large projects in Lisp, I don't get why people don't use the dynamic card
as often there. What I have seen happened on badly engineered large projects
is people blaming it on dynamic typing because there is no documentation and
no structural integrity in the project. But the people behind those projects
would not be able to do much in any language IMO. In a sense, it allows for
poor programmers to do more.

The speed issue is a significant one, but not usually for the reasons given.
The big drawback of being slow means a lots of its implementation is not
written in python.

IDE/debugger is another issue, although some of it is a matter of people not
knowing the tool. Especially on bad codebases, even something as simple as
pyflakes running in the background is invaluable, and many people don't use
this.

~~~
dkarl
_What I have seen happened on badly engineered large projects is people
blaming it on dynamic typing because there is no documentation and no
structural integrity in the project._

This can be a problem in static languages with good type inference, too. When
reading code in older static languages like C++, you'll find a bunch of
variables and types declared, but powerful and concise languages such as Scala
have much less use for intermediate variables, and type inference means that
intermediate variables are almost never declared with a type. Field types and
method return types often aren't declared either. I don't know if this is a
good thing because it forces you to read a lot of code, or if it's a bad thing
because it forces you to read many unrelated bits of code when you're trying
to get something simple done.

~~~
spitfire
That's because C and C++ are not static languages. Only people who leaned C
and C++ first think they are.

~~~
josephlord
They are statically typed but only weakly typed (casts, void etc.) as is Java.

Python is dynamically typed but again weakly.

ML is strongly and dynamically typed.

Anything that treats anything as a string or automatically casts from strings
fills me with terror for general programming.

~~~
abdulhaq
No, python is strongly typed.

~~~
masklinn
You should avoid using those words, it merely marks you as somebody without a
clue. I'm guessing your grandparent is already lost so there's no point in
warning him.

~~~
prodigal_erik
C and C++ are weakly typed because you can do things like

    
    
      int x = 42;
      printf("%c\n", *(char *) &x);
    

that is, access the underlying bits which represent a value as if they were of
some completely different type. The results are deliberately not standardized
and vary with your machine. Python doesn't provide any way to do this; at
worst you get a TypeError for a conversion that isn't implemented, or
AttributeError for a slot that an object doesn't have.

Implicitly parsing strings to produce numbers isn't weak typing, merely
reckless and prone to mistakes. Weak typing can corrupt the state of your
program so severely that even correct code begins to malfunction.

~~~
masklinn
> C and C++ are weakly typed

This, in and of itself, means absolutely nothing. And neither does:

> Implicitly parsing strings to produce numbers isn't weak typing

There is no such thing as a widely accepted, let alone formal, definition for
a strong/weak axis, every other guy out there has his own personal definition.
What the bloody hell is the point of words for which no two persons share the
same definition? No point. None at all. See comment above, it merely marks you
as a guy without a clue.

------
orangecat
Python has been my favorite language for many years, while the last few months
at work I've been writing a lot of JavaScript. I've found that JS has exactly
one advantage over Python, which is usable function literals. And that turns
out to have a surprisingly large impact. It's convenient and natural to create
"anonymous classes" that use closures to store their state, while in Python
you'd have to manually create classes and manually copy the variables in
__init__. I really wish Python could gain something like that while retaining
its many advantages.

~~~
btilly
What do you mean by "usable function literals"? Because Python has them, even
if you have to do a bit of work to get them.

    
    
        def demo (n):
            def multiplier (m):
                return n * m
            return multiplier
    
        x5 = demo(5);
        print x5(4)
    

You can do anything in the inner closure that you might want. The only
surprise is scoping - if you want to modify state you need to use a mutable
data type because otherwise you'll be instantiating a private variable. But
that hoop is easy to handle.

    
    
        def demo ():
            counter = [0]
            def increment ():
                counter[0] += 1
            def peek ():
                return counter[0]
            return (increment, peek)
    
        (increment1, peek1) = demo()
        (increment2, peek2) = demo()
        increment1()
        increment1()
        increment2()
        print peek1()
        print peek2()
    

So there. Function literals. They work.

But, you say, you really want anonymous classes? Well look up metaprogramming
then. Python really has quite good support for it. There is no trouble
creating anonymous classes on the fly with their own attributes, functions,
and so on. They can even inherit from each other.
[http://www.voidspace.org.uk/python/articles/metaclasses.shtm...](http://www.voidspace.org.uk/python/articles/metaclasses.shtml)
might be a good starting place on this for you.

(Note, I do not recommend metaprogramming unless the solution you make will be
reused a lot.)

~~~
orangecat
_What do you mean by "usable function literals"?_

lambdas. Your example isn't a literal, it's just a declared function named
"multiplier". Sure, it has equivalent functionality, in the same sense that
Python could remove collection literals like [1,2,3] and you could still
create lists and maps by hand. But that would be silly.

 _even if you have to do a bit of work to get them_

And that work means that useful techniques become too unwieldy to use in
practice.

~~~
btilly
I am also annoyed by the omission of a truly useful lambda. But the rest of
the language is compact enough that I've never found techniques relying on
closures to be unwieldy in Python. _shrug_

------
calpaterson
This thread mostly contains superficial complaints (whitespace, self, the GIL)
that are either explicit design decisions or not important for the kind of
programming Python wants to address. Some more important problems that
materially affect normal and sane use of Python:

\- Broken scoping by default (the thread does raise this)

\- Unicode is very painful in python2 (addressed very well by python3)

\- Duck typing sometimes prevents early detection of genuine programming
mistakes because of overuse: False + 1 == True

\- No good isolation tools (virtualenv, the most common tool, silently fails
to isolate dependencies when moved, which is obviously makes it tough to
deploy using it)

\- Poor packaging tools (only a few tools than they all have serious
limitations such as not being able to package c-extensions).

\- Some of the standard library is downright terrible. csv and robotsparser
are good examples. This has the pernicious effect of widely-distributing
libraries that have subtle but serious drawbacks.

~~~
tarekziade2
> Poor packaging tools (only a few tools than they all have serious
> limitations such as not being able to package c-extensions).

Python stdlib will let you package a C extension. I am not sure why you think
the opposite. <http://docs.python.org/extending/index.html>

> No good isolation tools (virtualenv, the most common tool, silently fails to
> isolate dependencies when moved)

If you mean it's not relocatable, there's a new option for this
[http://www.virtualenv.org/en/latest/index.html#making-
enviro...](http://www.virtualenv.org/en/latest/index.html#making-environments-
relocatable)

But being not relocatable is not really an issue, as you can simply re-run
virtualenv in the new place. All libs you previously installed will work
without having to install them again

> Some of the standard library is downright terrible. csv and robotsparser are
> good examples. This has the side effect of widely-distributing libraries
> that have subtle but serious drawbacks.

Some stuff in the stdlib are not good that's true, but we have a gigantic
library ecosystem at pypi.python.org will very well written piece of libs.
Using Python seriously, I have never ever felt the serious drawbacks you are
talking about _except_ with tarlib in python 2.4 which was seriously broken.

~~~
calpaterson
> Python stdlib will let you package a C extension. I am not sure why you
> think the opposite. <http://docs.python.org/extending/index.html>

But c-extensions aren't put into the same package so you still have to include
the shared object files yourself so it's not really a package. One of the best
things about the JVM's jar is that you can pack all your other jars into one
jar for deployment.

> If you mean it's not relocatable, there's a new option for this:
> (--relocatable)

"In theory virtualenvs have a --relocatable flag but that one is heavily
broken and conceptionally can't work properly because it uses the system
Python interpreter to switch to the intended environment."

<http://lucumr.pocoo.org/2012/6/22/hate-hate-hate-everywhere/>

> pypi.python.org

Yes, it's great, but I'm talking about the standard library. I really wish
some of the worse parts of it would be improved or removed.

------
njharman
If you learn to like Python, you will learn to hate other languages. :)

The stdlib. It has some great parts and overall is just good enough (and
desire to not break everyone's code) to not cause revolt and wholesale
replacement.

FTPlib is atrocious.

httplib/urlib mess -> requests

os os.path, shutil subprocess is a ridiculous mish-mash of legacy, obscurity
and surprising behavior. One example. os.mkdir (but only the leaf, and
exception if it exists), want mkdir -p behavior. Is that an option to
os.mkdir, fuck no! We need a whole new function for such dramatically
different feature. Must be called mkdirs, fuck no! That would be too easy to
remember and no one every look at our beautiful docs. os.makedirs is the
_obvious_ choice.

~~~
Alex3917
"If you learn to like Python, you will learn to hate other languages."

I think it would be more accurate to say that if you learn other languages,
you'll learn not to hate Python. Python is kind of mediocre in a lot of ways,
but it's the only language without any deal breakers.

~~~
pbiggar
Clojure also lacks deal breakers. Python was my least hated language until
Clojure.

~~~
kisielk
The Clojure language is great, but the dependency on the Java ecosystem and
the JVM are deal breakers for me.

~~~
pbiggar
Why? To be honest, I used to think that, but then I actually tried it and
haven't had any problems there.

~~~
Chris_Newton
If you’re working on embedded code, the overhead for something like the JVM
could easily be prohibitive because of the size.

And if you’re working on anything that needs to do a small job quickly, such
as command line tools as fauigerzigerk mentioned, the overhead for something
like the JVM will almost certainly be prohibitive because of the delay at
start-up.

------
cageface
The scripting languages are all really more alike than different.

The main downside of Python compared to, Ruby, for example, is that Guido made
some serious mistakes in the initial design and in the process of fixing them
added a lot of extra complexity to the language. Python doesn't cleanly "fit
in the head" the way Ruby or JavaScript do, at least for me.

But instead of wasting time micro-optimizing in such a narrow language space,
pick Python or Ruby or whatever and spend your extra cycles on something
different enough to be worthwhile like Go or Haskell.

~~~
recursive
I learned python first, and I have the same complaint about ruby. When I was
attempting to learn ruby, the subtle differences between blocks, procs, and
proc.news, or whatever they are, seemed arbitrary and required too much
thought to understand for my taste. In my brief exposure to ruby, that was
symptomatic of a general trend in the language that there seemed to be many
ways to accomplish a task, without a clear reason for the distinction. That's
fine if you're writing code, but imo that's a feature that makes reading a
language more difficult.

~~~
VeejayRampay
You don't have to learn every single way to achieve a task though. Just
sticking to simple blocks will solve 95% of the issues for you. If you want to
get into more detail, Ruby will grow with you. I've sincerely yet to
explicitly use lambdas or Procs and I've been coding Ruby through Rails for a
few years now.

~~~
recursive
Like I said, that's fine if you’re only writing code. It doesn't stand up so
well if you need to read code also. The author of the code could use any
feature the language provides.

------
LBarret
I have built an app of over 500k sloc in Python.

In retrospective, I feel the python as a language was a good choice, it helped
us move very fast and do a lot of things :

\- One good pythonner is very productive

\- It was easier to get someone aboard, it is easy to get python and to
reasonnably efficient with it.

\- there are libraries for everything.

\- going to cython or c++ was always an easy alternative for those crtical
part of the code.

The only cases where python can be problematic are :

\- high reliability code like trains or planes software, because python code
is not provable.

\- very high performance, where the slowness of python _in the not critical
part of code_ can be a problem.

Besides, It doesn't protect you against the classic problems of a big codebase
built by a different of people over a period of time. Tools like pynocle or
pylint were good for this.

So, in the end, python has obvious weakness. Most of the time It seems like a
solid choice (among others). Right tools for the job, etc.

------
yen223
I never did understand why True and False are capitalized.

[EDIT: Turns out it's because all built-in constants are capitalized:
[http://stackoverflow.com/questions/521476/why-true-false-
is-...](http://stackoverflow.com/questions/521476/why-true-false-is-
capitalized-in-python) . Learn something new every day. Still don't like it
though.]

Also object-oriented programming in Python is very awkward. Then again, if I
wanted OOP, I'd use C#.

~~~
Wickk
How do you find OOP in python awkward? Out of curiosity.

~~~
rb2k_
I always found it weird that they use len([1,2,3]) rather than [1,2,3].len

(no, I don't want to call [0,1,3].__len__() . Why would I want to add all of
those underscores.)

~~~
FuzzyDunlop
Similarly weirdly, the string join method really confuses me:

    
    
        ''.join([1, 2, 3])

~~~
eru
That actually makes sense. Because the joining is something that a string
knows how to do. Why should arbitrary lists know about string manipulation?

By the way, your example has an error, since you can't join a list of numbers.
You can only join lists of strings. I.e.

    
    
        ' '.join("Hello", "World")

------
tptacek
"It's far from the metal"? No it isn't. It has _ctypes_ , which is one of the
best FFIs I've worked with. I wrote a trampoline-injecting kernel debugger in
it. I don't love Python, but that answer disqualifies itself.

~~~
Sukotto
I don't know what _trampoline-injecting_ means and my googlefu has failed me.
Would you briefly explain what you mean?

~~~
tptacek
Instead of implementing breakpoints with INT 3, which relies on the OS's debug
event support, our debugger injected new basic blocks into the program to
pause the target, perform I/O with it, and redirect it to other code paths.

You should have no trouble looking up what a "trampoline" is, but I'm abusing
the term a bit.

~~~
gruseom
So you made a debugger below the OS by instrumenting the target program to do
debuggery things? That's pretty cool. But at what granularity did you inject
the code? Presumably not around every single instruction. But if it was just
on demand wherever the user set a breakpoint, how would you implement
stepping?

~~~
tptacek
We didn't do stepping (at least, mine didn't); instead, we tended to do things
like Detours, where we'd target a broad set of bblocks in the program and
either log, or snapshot the process when they were hit.

There is a pattern for single-stepping using similar techniques: "user mode
single stepping".

One thing to bear in mind: it was easy for us to do this in part because
crashing the target program was not a big deal for us.

------
tikhonj
My biggest problem with Python is not that it's a bad language but that it
isn't a great language. Why is this an issue? Simple: it's one of the most
highly rated--and, frankly, _over_ rated languages today. And, try as I may, I
can never seem to get away from it: at least in my circles, it's even _more_
endemic than Java!

I really wish people liked OCaml or Haskell that much instead.

~~~
snogglethorpe
Yeah. Python has an awful lot of warts, considering the way so many people
fawn over it.

Really the main strength of Python is not the language at all, but the huge
number of libraries written for it, and the wealth of tools and "community."
Fair enough, it was in the right place, at the right time, but if history is
going to throw its weight behind something, it _is_ a little annoying when
that thing is rather mediocre...

------
d0m
For what python has been created for, there are really few if any drawbacks.
This is still my go to language.

Something I wish python had a better support would be truly anonymous function
I.e. you can't do:

    
    
      lambda x: raise "foo"
    

It's also very hard to write nested callback (Some pythonists like to argue
that is actually a _good_ thing).

Lastly, I wish the functional paradigm part of python was more consistent.

But all in all, I love python and I find it very hard to switch to something
new without missing it.

------
lazydon
While we are on the subject, I find that this answer provides with much better
arguments - <http://stackoverflow.com/a/431341>

It's an interesting read - he begins with "The problem is that it is not as
good as it is made out to be, in other words it suffers from a degree of hype.
I'll try to argue this point."

~~~
nahname
Mostly it is the age old complaint, can't build something big in a dynamic
language. The evidence is that I don't know of anything big in a dynamic
language. Not exactly great points against python when the argument boils down
to, "all dynamic languages are bad."

------
hannibalhorn
Nobody has mentioned the inconsistent naming conventions in the standard
library, which always drove me nuts.

~~~
ninetax
Could you give some examples?

~~~
hannibalhorn
It's not a secret at all, PEP 8 even acknowledges it - see
<http://www.python.org/dev/peps/pep-0008/#naming-conventions> \- and of course
attention to backwards compatibility is a good thing.

\- usually constants are capitalized, but math.pi and math.e aren't

\- the Decimal class has methods like is_nan(), and generally puts underscores
in the method names, while the math package provides methods like isnan()

\- even within the same package, you have cases like itertools.groupby() and
itertools.combinations_with_replacement()

Not a deal breaker, it's just a drag when you only work in a language once
every few months, and you constantly have to look at the docs to know whether
something is alllowercase, ALLCAPS, camelCased, with_underscores, etc.

------
raverbashing
\- Multithreaded development; multiprocess is being favored (as well as event-
driven) and there are some helpful modules for it

\- Unicode (at least for Python 2)

\- Debugging is a little behind other languages (pdb works)

\- removal of map/filter in place of list comprehensions (they are certainly
better but not faster)

~~~
emidln
map and filter still exist. reduce was demoted into the stdlib instead of
being builtin in 3.x.

list comprehensions generalize to other types (generator expressions (aka
"lazy sequences"), set comprehensions, dict compresions)

Compare this syntax (using dict comprehensions in 2.7):

    
    
      {k:v for k, v in something.iteritems() if v == 3}
    

to this syntax using map/filter:

    
    
      dict(filter(None, 
               filter(lambda x: x if x[1] == 3 else None,
               something.iteritems()))
    

More frustrating to me is that there isn't an imap/ifilter builtin (I
understand that it's in stdlib, I'm just lazy).

~~~
masklinn
> More frustrating to me is that there isn't an imap/ifilter builtin

FWIW, alongside the demotion of reduce to the stdlib Python 3 changed that,
the builtin `map` and `filter` now return lazy "views" (as do e.g.
`dict.items`, `dict.keys` and `dict.values`):

    
    
        # python 2
        >>> map(sys.stdout.write, ['foo', 'bar', 'baz'])
        foobarbaz[None, None, None]
    
        # python 3
        >>> map(sys.stdout.write, ['foo', 'bar', 'baz'])
        <map object at 0x10071cfd0>

------
ErrantX
Speed, definitely. Although in defence Ive always found python very easy to
"hack".

Writing a C extension to do computationally intensive work is fairly simple.

With its versatility and extensability I once threw together a proof of
concept password cracking cluster in a week. Redis for queues/data, MySQL for
data, hashing code in a C extension, flask for the web interface. Cross
platform and lovely :-)

Threading is the only real let down for me.

~~~
masklinn
> Writing a C extension to do computationally intensive work is fairly simple.

Even more so with Cython, which does most of the hard work for you.

~~~
Xixi
Or the recent numba: <https://github.com/numba/numba>

------
kanja
That thread is depressing - most of the things people are complaining about
are conscious design decisions made by the python team. EG Complaining about
self - explicit is better than implicit is a core property of python. I feel
like `import this` would answer a lot of these.

~~~
orangecat
Practicality beats purity. Python should support better function literals for
the same reason that it supports the "implicit" [1,2,3] instead of making you
explicitly create a list and call append. I'd say self falls into the same
category, although I haven't found it as much an annoyance as some.

------
16s
I would say that Python has a feeling of inconsistency at times compared to
other scripting languages. I don't mean this as a criticism. I like and use
Python a lot for work and personal projects. Here's an example of what I mean
by inconsistent:

 __ _len(a_string)_ __

 __ _a_string.lower()_ __

 __ _a_string.upper()_ __

So here, there's a global, generic function len() that returns the length of
the string while in the other examples, the string has methods such as
.lower() .upper() etc. Why not have a_string.length()? I understand that
generic functions are more efficient and even proper in OO. It just causes the
feeling of inconsistency when you use the language a lot or when you are
teaching a child how to program and have to explain the difference and why
some things are methods while others are not.

Also, some python idioms (such as slicing) are not intuitive for many use
cases. Here's an example of the traditional way in which to reverse a string
in Python by slicing:

 __ _a_string[::-1]_ __

In Ruby, you type __ _a_string.reverse()_ __and that is much more intuitive to
a child when compared to the slicing in Python.

Having said all of that, I love Python and use it daily and encourage others
to do so as well. I

------
pbiggar
My least favourite part of python (I'm overwhelmingly a fan, and it's probably
my favourite language after Clojure) is the deliberately limited functional
parts. Take list comprehensions, they work for simple things, but when you
want to make it more complex, it wont let you break it over multiple lines, so
you have to rewrite it into a for loop. Makes debugging awkward.

~~~
masklinn
> it wont let you break it over multiple lines

?

    
    
        result = [
            (value, process(value), process(key, value))
            for key in generator
            for value in generate(key)
            if some_condition(key)
            if other_condition(value)
        ]
    

or did you mean something completely different? Maybe the problem of not being
able to use _statements_ in comprehensions (or lambdas)?

~~~
pbiggar
Right, I meant using statements, sorry. It's been quite a few months since I
wrote python, so I think I've forgotten most of the details.

------
tocomment
Did anyone mention the Gil? I'm hearing more and more complaints about that.

~~~
yen223
Having worked with multi-threaded applications in other languages, I'm
starting to think that the GIL is more a good thing than a bad thing.

Seriously, threads are evil.

~~~
w0utert
The GIL does not make threads less evil than you apparently already find them,
it just makes them a lot less useful.

Threads in Python still have all the pitfalls and complications they have in
other languages, it's just that they cannot use multiple cores or hardware
threads. So you get all the evil bits (race conditions, deadlocks, having to
protect access to shared state, etc), but you miss out on all the performance
benefits threads can have on parallel hardware.

In Python, threads are only useful as an abstraction of things that have to
run concurrently, even though they never do.

~~~
masklinn
Not that I want to distract of your righteous rant, but threads also work
without issues when doing mostly IO: C libraries and implementations are free
to release the GIL (and often do). So if you want to e.g. fetch a bunch of
things concurrently, those will be done concurrently. And your

> have to run concurrently, even though they never do.

is way off base.

Likewise, if you're doing CPU-heavy crunching (likely implemented in C or
Cython), you can release the GIL and let the interpreter run some other
bytecode at the same time.

------
silverlake
I was a Lisp/Scheme programmer. I use Python only because Norvig wrote that it
isn't so bad. But I curse out loud every time I type in 'self'. I hate the
lambda limitation (only expr). The scoping rules continue to confuse me. It's
a good language if you're coming from C/Java. But it's a poor language if
you're coming from Lisp/Smalltalk/ML.

------
pnathan
I've written about this before here:
<http://news.ycombinator.com/item?id=3580590>

Fundamentally, I believe Python's drawback is that it appears to draw heavily
from the ABC history it has, and wasn't designed for power and flexibility.

I'd rather use Perl, Ruby or Lisp.

------
DonnyV
To this day I still hate the fact that wrong spacing causes a compiling error.

------
anuraj
Performance and type safety which is true for any scripting language

------
lectrick
self __init__ self.__init__ self self __init__ self

------
lani
it doesn't wear a suit

~~~
topherjaynes
Is this a quote from somewhere? I laughed, and now want to make a opensource
project suitupy

------
rjh29
My favourite critique of Python: [http://www.quora.com/What-are-the-main-
weaknesses-of-Python-...](http://www.quora.com/What-are-the-main-weaknesses-
of-Python-as-a-programming-language)

------
recoiledsnake
Nice to see programmers.stackexchange.com being used for things like this.
Hopefully it will put a rest to the same top comment on HN Stackoverflow
stories complaining about how such questions are booted off Stackoverflow.com

------
monochromatic
Mutable default arguments. 'nuff said.

~~~
gizmo686
Ironically, the one time where I noticed this bug was while testing a
component, whose only use involved me emulating the behavior of mutable
default arguments on a higher level. I still think it is a horrible system. My
strong opinion on it might be because I spent hours looking at our
c-extensions for the source, because the previous two 'language bugs' I ran
into were both in our c-extensions, where we had a type that could not cast to
it self, and someone thought it was a good idea to make ~x mean x __-1.

