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.
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.
Is it not the case that in Lisp people tend to use values — lists of (probably immutable) data — rather than objects? Objects are in and of themselves their own flavor of custom, specialized language for interacting with a data structure. In Lisp, the language for interacting with lists of lists or what have you is, well, Lisp.
IME duck typing is not a real answer in this situation; that helps when you are programming to an interface in the standard library, or in an API you are using. Otherwise I end up hunting down information about a data type through N layers of method and function calls. Not a good time. :( This actually drove me towards Go as a language with comparable productivity but with a type checker, et al.
I'm not sure where Lisp macros fit into this, if they do. I expect they have a tendency to boil down frequently repeated patterns into something very compact and less error-prone.
As for IDE support, Rob Pike suggested (not in so many words) that if you need an IDE for your programming language, it suggests that something's probably wrong with that language. He's not disputing that people genuinely need them, because yes, jesus h, I really do need Eclipse when you're programming against a reasonably large API. I think I find this line of reasoning more convincing than I would have, say, a year or two ago.
Anyway, for my part, ST2 was enough of a Python IDE for me. And thanks for the tip about Pyflakes, by the way. There's guard[1], which I figured you could rig up with python -c or whatever the flag is to compile. Pyflakes looks easier.
Exactly. Dynamic typing can provide a temporary fig leaf for bad design in ways where static type checking would be less forgiving. Doesn't make dynamic typing wrong, it just means that bad programmers can get in over their heads more completely and more quickly.
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... 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.)
- 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.
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...
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.
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.
Not only does it make bindings awkward (and sometimes broken, in different ways depending on the way "scope inference" is implemented) and tends to hide errors (e.g. typo) or generate them much later than possible (even though lexical checking is very cheap to perform at parse time, with explicit scopes), it has pretty much no actual benefit I can think of.
Especially in Python where assignment is a statement, not an expression, so it's not like explicit scoping would prevent putting assignments in place they're currently allowed.
[0] and it's one of the things I find utterly retarded in coffeescript.
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.
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.
I find the severe breakages and insanities of Javascript (such as tracking what `this` is) take much more brain-space than Python ever did, personally.
I've been replacing my shell scripts with Haskell scrips lately and the transition is going well. Soon the only two languages I will ever need are Haskell and elisp!
I imagine the order on which you learn is important. I learned OOP with Smalltalk and C++ not only didn't fit in my head, it created an impressive allergic reaction. It took me 8 years to be able to get back to it and finally learn.
And it still feels a horrible kludge.
I learned Python before I had contact with Ruby and I find the irregular syntax hard to parse.
Guido always said he could only afford to break python once but it's not clear to me he'll even get away with once.
So I don't understand your comment about it being a narrow language space.
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.
[EDIT: Turns out it's because all built-in constants are capitalized: http://stackoverflow.com/questions/521476/why-true-false-is-... . 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#.
Which is not just reductionist, but downright silly. C# is not a very good OO language, in the same way Java isn't.
When I want OOP, I play with Smalltalk. Or Self.
I really wish people liked OCaml or Haskell that much instead.
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.
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."
- 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)
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.
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
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.