Hacker News new | past | comments | ask | show | jobs | submit login
First Impressions of Python from a Java Developer (jeffbail.com)
73 points by jbail on Nov 8, 2010 | hide | past | favorite | 97 comments



The thing that really made my jaw drop the first time I saw it was list comprehensions.

    allowed_usernames = [user.username for user in all_users if user.is_admin()]
This Stack Overflow answer makes it seem like Java developers should be at least impressed with them as I was: http://stackoverflow.com/questions/899138/python-like-list-c...


This feature is of course lifted from Haskell - another jaw dropping language.


Yep. Python has a wonderful habit of taking the awesome features of other languages and expanding on them.

List comprehensions were added in 2.0, generator comprehensions were added in 2.4, and dictionary comprehensions came in 2.7


Just found a reason to upgrade to 2.7...


"Haskell is a scripting language inspired by Python."

:)

http://www.haskell.org/pipermail/haskell-cafe/2010-November/...

(joke)


You can do similar in scala, either

  val allowed_usernames = all_users.filter(_.is_admin()).map(_.username)
or

  val allowed_usernames = for(user <- all_users if user.is_admin()) { yield user.username }
And still get all the of goodness of Trivial jvm/java compatability...


Or Clojure... (or... or... or...)

    (map :username (filter admin? all-users))


Or Clojure again

    (for [username all-users] :when (admin? username))


Nothing against scala, but you can program in Python and get all the goodness of JVM compat by simply running your programs in Jython...


Jython is behind current python implementations. If you're comfortable with being compatible up to python 2.5 then go right ahead. But if you need 2.6 or 2.7 compatibility, Jython is sadly not an option.


In Ruby, with ruby underscore (http://bit.ly/9dwWAX), you can write it as:

    all_users.select(_.is_admin).map _.username
Other languages have similar ways to write it concisely as well (http://bit.ly/a6QmgL). Coffeescript (which compiles to javascript, and therefore, can run on Rhinon inside the jvm) in particular:

    allowed_usernames = user.username for user in all_users when user.is_admin()
Yeah. Reminds me of http://gag.googlecode.com/svn/trunk/javadoc/com/google/gag/a...


In Ruby 1.9, or Ruby 1.8 w/ ActiveSupport, you can use the & operator, which coerces it's argument (in this case, a symbol) to a Proc:

    all_users.select(&:is_admin).map(&:username)
This is a common idiom with a fantastic writeup at http://weblog.raganwald.com/2008/02/1100inject.html


Actually on ruby 1.8.7 the proc coercion is default. No need for active support. And yeah, ruby underscore is overkill for this trivial example.


This blew my mind when I first came across it:

    deck = ['%s%s' % (n, s) for s in 'HDCS' for n in '23456789XJQKA']
It creates a deck of cards.

Also, you can easily shuffle the deck using the standard library.

    import random
    random.shuffle(deck)


Yes, terseness is definitely not among Java's virtues. Your way looks a lot more fun to write than mine -- it's amazing what a little well-placed syntactic sugar can do.


one the few reasons i like jython too!


.NET languages (C#, powershell, for example) have list comprehensions as well. They seem to be unappreciated languages amongst the "cool kids" due to their Microsoftian origin.


Or maybe it's because powershell and C# only run on windows and are not open source and we're not interested in using a technology that is playing catch up with a moving target (mono).


Since you claim C# only runs on Windows and yet mention mono in the same sentence I'll pretend you said instead that mono is not production ready (which I think I could buy, at least for SaaS).

As far as "playing catch up with a moving target", I don't see how that's terribly relevant, the end result is still a platform that continues to improve and advance. If the C# code that runs on Windows and mono is still more advanced than, say, Java or Perl, and continues to advance (even though not as fast as C# on Windows alone) then that's still a benefit. Given the advent of monotouch and the coming of monodroid it seems like even a hard-core MS hater could come to appreciate C#.


> If the C# code that runs on Windows and mono is still more advanced than, say, Java or Perl

The problem is that it's not. You can do anything you want when it comes to SaaS using python, ruby, php, node or java. Actually those have huge open source communities with tons of libs available to make work faster. This is not the case of C# and if it ever gets there, it probably won't be any better. So again, I don't see any reason to use it, and plenty of reasons not to and being a "hard-core MS hater" would probably come at the bottom of the list of reasons not to use C#, don't try to justify the lack of interest in MS by some kind of imaginary persecution. But to each his own , if you're happy with it go for it.


Seriously? I mean, I'm doing my job using the, let's call them, open-source languages: javascript, php, bit of python, java and perl, but, still, I would say that C# is better than most of them, both in terms of the lanuage syntax, features and such, as well as in terms of the quality of libraries. That it's sort of Microsoft-platforms-only keeps me away, but I have to give a credit where it's due: C# is a great piece of technology.


Seriously. C# syntax looks too much like Java, python and ruby have much better syntax IMO and they have way more libraries than C#. But again, to each his own.


well, ruby and python, in your original post you've said c# is no better than java or perl, that makes "a bit" of a difference...


In my original post I said everything you can do with c# you can also do with perl when it comes to building a SaaS. Is there some kind of website that can only be built with c# but not perl? I'm curious.


It's mostly a "niche vision" effect. I know a lot of cool kids that do use C#, list comprehensions, Linq, and appreciate .Net a lot.

Some of them also believe Python, Ruby etc are for kiddies :)


My first impression is that this guy is 10 years late!

And I agree that it's funny for a Java programmer to be able to read a file with open('bleh').read() instead of that 15 stream buffer stream reader stream whatever line of code.


I never really understood how the developers and maintainers of the Java language could put up with the overly complicated disaster that is file I/O. They've managed to take something that's relatively simple in most languages and turn it into an utter disaster. I was shocked, years ago, when I was learning Java after having lived in C++ world.


...and if you're processing text files line by line, it isn't even necessary to call read() or readlines() on the file, since a file object supports iteration. You could say:

    for line in open("todo.txt"):
        # do something with line


You could also

    [ do_something_to(line) for line in open('todo.txt') ]


Although you'd probably want to replace those square brackets with parens to make it a generator, if you're dealing with a largish file.


Indeed. Hope it's not a huge file.


Default Java File I/O is pretty horrible but like a lot of things about Java, the widely-used Apache Commons makes it better:

String fileContents = FileUtils.readFileToString(new File("blah"));

Still not quite as concise as Ruby/Python/etc though.


Surely late is better than never.


I am admittedly late to the party. I went to a university where they taught Java (and unfortunately not Python). For the last 10 years, Java has paid the bills, and it still does, so I'm not knocking Java. I stuck with it for so long because I felt that it took that much real world usage to get a good grip on the language.

But you are right --- I'm definitely not the first developer to have had that "moment of zen" when opening files in Python, but hopefully I'm also not the last.


So welcome :) In a couple of months, if you really want to have that "moment of zen" again, give a chance to SICP (it's a wonderful book) which will teach you functional programming and Scheme in the same time.


> The one pitfall for block indenting in Python is reading online documentation. The block indenting gets screwed up sometimes.

Sometimes, pressing "view source" in the browser and looking at the HTML will reveal what it was supposed to look like.


Mind, this is not unique to Python. It's a bit more irritating in Python because indentation is significant, but I've seen a lot of unindented samples of other languages with correspondingly reduced readability. For some reason, I've most seen such sloppiness in presenting Javascript code.


Yes, but the reduced readability is an easy fix in that case. You can copy the code into an editor and indent based on the braces or have your editor auto-format the code. Badly formatting code in other languages does not change the meaning of the code as it does in Python.


I'm not sure what your point is, as I already acknowledged that in the comment you're responding to, while making it clear that my concern was readability of code examples on a web page. Are you going for a cheap "gotcha"?


My point is poor readability of samples in other languages is a really simple fix. I have cut'n'pasted many code samples into editors just to re-intent them for reading. With Python, sadly, it's just not possible to that roboticly.


I do not think the author was not aware of this, it was more of him digressing.


I think that being able to fit the whole source on a single page more than compensates for the occasional indentation problem.


I never understood why Java never got some nice utility functions for dealing with common stream actions such as looping through an InputStream or slurping a text file. Every developer ends up carting around their own version of these functions when they should just be in the standard library. Many complaints about Java's verboseness have to do with this type of boilerplate that could easily be hidden away in utility functions.


Isn't that what Apache Commons is for? It's sad that you have to resort to that but at least someone stepped up to the plate.



util.Scanner

I recently learned about them and they simplify a surprising number of simple parsing tasks.


In Java, that would take a handful of code, a try/catch block, a loop, some sort of buffer and would ultimately create much more verbose, much less readable code.

How do you get away with none of this in Python? You need a try/catch block to catch exceptions on open and read don't you? There's no guarantee the file exists, or you have permission, or enough memory to read the file.

And while you don't necessarily need a for-loop to process the data, you often will.


      You need a try/catch block to catch exceptions on open and read don't 
      you? There's no guarantee the file exists, or you have permission, or 
      enough memory to read the file.
Doing a try / catch implies that you can recover from it.

That isn't the case most of the times (you cannot get extra permissions to a file, you cannot recover from not having enough memory, and if the file is missing that's a bug).

What usually happens in both Java and Python is that you have a top-level try/catch that catches everything and just does logging.

The difference is that in Java you catch and re-throw the exception, or put the exception type in the method's interface, which IMHO leaks encapsulation. Or just turn everything into RuntimeExceptions with a little compiler-plugin magic.

Either way, checked exceptions are a big fail.


Doing a try/catch doesn't imply anything, except that an exception occurred that you caught. Behavior after that is completely app dependent.

Top-level try/catch blocks that simply do logging and nothing below that may not always be a bad idea, but its usually a sign of a poorly designed app.

And why can't you get extra-permissions or recover from not having enough memory? I've certainly worked on systems with the later, where we catch an OutOfMemoryException and then do some stuff we're required to do -- including in some situations to get memory back (which is for example, why we'll often pre-JIT and keep loaded code required to free up memory).

Checked exceptions are a big fail, but largely because they're a broken way of thinking about exceptions (and why Java was the last major language to have them).

EDIT: I glossed over the fact that you may have been actually getting at which is the requirement associated with checked exceptions. You're absolutely correct there. No argument from me. I wasn't think of that originally, as I'm not a Java dev.


> Doing a try/catch

Doing try/catch tells the compiler you know what you are doing. I prefer compilers that take that as a given.


> How do you get away with none of this in Python?

It's optional.

You don't have to catch any exceptions (unlike java), however if you want to you can catch, separately, any one of the dozen exceptions that could be raised (IOError, permission error, memory error etc.).

One reason I love python is that the common use case is easy. 90% of times people read from files they don't need to handle every exception there and then, ergo python makes that possible. This makes python much more enjoyable, productive and easy to use.


Exceptions in Python are automatically runtime errors and will stop execution with a useful error message if they aren't caught. Is this not true in Java?

In Python, you don't need to add a try/catch block unless you specifically need to do something and continue execution after an exception.


Given the limited set of things he goes over (with the exception of block indenting trouble) you could replace "Python" with "PHP" and still have the same article. Don't crucify me, just pointing that out.


Or any semi-modern scripting language, for that matter.


Yep. I went to read it expecting some insight (as I don't know Java) but was disappointed to see the article was so generic.


I looked into groovy recently, and even as a python fanboy I can see how awesome it is for someone who already knows java. It looks extremely close to both python and ruby, and you can drop down to java anytime, use java libraries anytime. It even has a pretty good rails clone called grails. Can anyone from the java community explain to me why it hasn't taken off more? Perhaps other JVM languages have stolen people away or split the people looking for something else. I suppose with a 1.0 release in 2007 vs the early and mid 90's for python and ruby respectively I should perhaps wait and see.


Groovy is nice in that it has nearly a zero learning curve (coming from Java) and provides all the benefits of a dynamic scripting language.

The downside is that it is dog-slow (up until recently, it didn't even use explicit types that were provided and always used reflection under the hood) and has some flaws in its design, which make it a bit unpalatable once you really start getting into it.

The consensus of my office seems to be that Groovy/Grails makes you twice as productive as Java for 2 days, then you loose it all again fixing some stupid, incredibly non-obvious problem on the 3rd.


I think speed has a lot to do with it, last time I checked Groovy was more than an order of magnitude slower than Java, whereas Scala (which has many of the same benefits as Groovy) was much closer.

A 2x speed hit might not be a problem, but for a lot of people (myself included), 50x is way too much of a penalty when you've got options that offer effectively the same benefits with vastly better performance. Maybe things have improved since I last checked it out, but I'm not sure.


I just finished building an internal web application for my school entirely in Java. From start to finish it took about eight hours, roughly the same amount of time it would've taken in Python/Django or RoR, thanks to the Play Framework.

Java doesn't need to be ridiculously verbose, others have mentioned much of that verbosity stems from basic functions not being included in the standard library. Python's opening of a file isn't any more elegant than Java's if you look at the code behind open(), it's just abstracted away.


There are some things that Java just is more verbose at. For instance, my pet peeve - accessor methods. Most other modern languages have properties, which allow you to only write special cases when you need them.


This is one of the things that Play does well; setters and getters are generated for you at runtime so you only have to write it as:

public Date submittedAt;

and set/get it as you would any other variable. Easily one of my favorite things about the framework, and saves my { and } keys work as well.


Groovy is very nearly to Java as Tcl is to C, which is great, but a common use case for scripts is as a command-line tool and no-one wants to cart around JVM startup times and memory requirements for that when Python is a already perfectly good language.


Scala and (to a lesser extent) Clojure seem to be more popular choices among (ex-)Java people nowadays.


Wait till he discovers the awesomeness of first class objects and functions.


Or iterators/generators and itertools.


One thing I dislike in Python's syntax is ":" at the end of some composite statements, i.e. "if X:" or "else:". "else" is reserved word, why do I need to append ":"?

Also how to do one-liners? ;)


Just like semantic indentation, ":" is ABC's heritage. It was discovered that newbie programmers comprehend block operations better when they end with ":".

http://python-history.blogspot.com/2009/02/early-language-de...


back in time, there was several schools for language syntax design for composite statements:

1. "Open" statements (Pascal):

  IF x 
    THEN s1
    ELSE s2;

  IF x 
    THEN
      BEGIN
        s1;
        s2
      END
    ELSE
      BEGIN
        s3;
        s4
      END

  WHILE c DO s;

  WHILE c DO
  BEGIN
     s1;
     s2
  END
The problem with this design was need to use blocks (BEGIN ... END) and complex rules in case of nesting.

2. "Closed" statements (Algol 68)

  IF x 
    THEN 
       s1;
       s2
    ELSE 
       s3;
       s4
  FI // END IF

  WHILE c DO
     s1;
     s2
  OD // END WHILE
You can see new kind of parenthesis IF-FI, DO-OD, etc.

I more like "closed" syntax. But C syntax with it's brackets blocks "{...}" instead of "BEGIN...END" made this less an issue.


You can have a one-line "if" statement [1]:

  if a == 42: print "Yes" ; do_stuff()
It's true that you cannot have a "else" statement on the same line, however.

But in some cases, you could use a conditional expression instead [2]:

  x = f() if a == 42 else g()
[1] http://docs.python.org/reference/compound_stmts.html

[2] http://docs.python.org/reference/expressions.html#conditiona...


in this case plain old C syntax is much more readable:

x = (a==42) ? f() : g();


I think that it's much more readable due to familiarity more than anything else. The C syntax for the ternary operator was the one thing that it took me the longest time to get used to when learning to program. I usually just ignored it because it was too hard to remember what it did. That said, I can easily read it now, but I still feel that the Python syntax is more understandable.

Which is more readable:

  > condition ? value1 : value2
or

  > value1 if condition else value2
Maybe the latter is just more readable to me because I'm used to reading Perl all day long that looks like:

  > die unless condition;
  > return true if condition;
  > return false
  >     if condition1 && condition2 && condition3;
That said, I'm also used to reading:

  > return condition1   ? value1
  >        : condition2 ? value2
  >        : condition3 ? value3
  >                     : value4;
and I still find the Python ternary operator more readable:

  > return value1 if condition1 else
  >        value2 if condition2 else
  >        value3 if condition3 else
  >        value4


Personally, I still have to think about what the ternary operator means every time I see it. It's just so nonobvious.


In this case I think the PEP8 spacing guidelines are counterproductive:

    f() if a==42 else g()
looks much more readable to me than

    f() if a == 42 else g()


You can also write it this way, which is more similar to C:

  x = (a==42) and f() or g()


I think the FAQ answers this question nicely: http://docs.python.org/faq/design.html#why-are-colons-requir...


As a non expert developer, I hate to see one-liners (using lambda expressions) when I am inspecting open source code.

So I would prefer they were not possible :)


While one-liners are almost always bad, the lack of non-crippled anonymous functions is the one thing that really bothers me about Python. They don't /have/ to be on one line; see Ruby's each blocks, for instance.


Every once in a while this will be brought up and debated to death...

See my last attempt in Feb 2009: http://mail.python.org/pipermail/python-ideas/2009-February/...


If you like Python but not the ":", check out the Cobra language: http://cobra-language.com/samples/WordCount/. FWIW I do like the ":", reminds me of a TODO list; in fact my plain text notes tend to look like Python ;)


You can do one liners with lambda functions in Python. e.g:

lambda x: x*2

http://diveintopython.org/power_of_introspection/lambda_func...


The colon is there to make it easier on editors that want to do auto-indentation. Their logic can simply be that if the previous line ends with a colon, then add a new indentation level.


Now we supposed to help editors? ;) I thought it should be otherwise... editors supposed to be helping programmers.

Programmers can learn syntax. Regular humans can't. Both Python and Ruby failed to provide a simple way of building internal DSLs. In Python humans need to be specific about indentation and ":" and in Ruby they need to remember all these stupid sigils.


lambda functions are pretty neat for one-liners.


What's the big deal about I/O in Java? I always thought things fit together pretty easily. Just want to read some integers from a file?

  Scanner in = new Scanner(new File(filename));
  while(in.hasNextInt()) {
    ...
  }
How about reading ints over a network connection?

  Socket sock = new Socket("foo", 10101);
  Scanner in = new Scanner(sock.getInputStream());
  ...
If you find yourself reading an entire file into an array, you want to easily access the lines of a file in an iterable fashion, or any of this other stuff, just write a 5 line method once and forget about it. Problem solved. There are features from other languages you can't replicate that easily in Java, but arguing about builtin methods is rather silly.


Totally nitpicking here but != and == should typically only be used when comparing primitive values.

For example, if you have an Integer object (not a primitive int) you should use .equals() and not == for comparison. The == is used for comparing references and not values.

That said, this only illustrates some extra complexity in Java.


Argh, the complexities of Java!

Integer a = new Integer(10);

Integer b = new Integer(10);

Integer c = new Integer(1000);

Integer d = new Integer(1000);

a==b is true

c==d is false


Sorry to break it out to you but you picked a bad example; the equivalent Python code has the same WTF effect:

Python 2.6.6 (r266:84292, Oct 17 2010, 15:53:05)

[GCC 4.4.3] on linux2

>>> a = int(10)

>>> b = int(10)

>>> c = int(1000)

>>> d = int(1000)

>>> a is b

True

>>> c is d

False


Wow! Really? (I'm not a Pythonator.)

Same reasoning as Java?


Basically yes, although it is not part of the language definition and should not be relied on. It's just an implementation artifact of CPython, and not only that but the threshold of which integers are cached changes for different Python versions.


It's simple, right? The result of <Integer> == <Integer> is undefined with respect to the value that is stored in the Integer object.


A bit more subtle than that- Java reserves singleton instances of Integer for values in the range -128 to 127. In these cases, the Integers will contain the same value and refer to the same object, so == works. It's not actually undefined behavior.


Maybe. C# uses != and == for string comparisons. Maybe the question should be: should an immutable string class be considered primitive considering how frequently it's used despite the fact it's internally passed by ref? I guess that debate is fairly academic and not very useful. Regardless, I agree with the author's point. I don't like having to use the "equals" method in Java for strings. It feels a bit outdated.


Agreed.

Thinking about it now, I would rather the inverse in a language be true, and have == be used for value comparison, and have a more wordy function for reference comparison. In my experience, I feel that its a much more common usage, and would probably reduce errors caused by programmers choosing the wrong operator. The only downside to this is that you then have to override an operator if you want to change equality comparison, instead of a function.


Python has == for value, and 'is' for reference -- that seems like a good solution to me, since it works for both "primitive" and "complex" data structures.


Blog posts like this are self-congratulatory wastes of time.

I would suggest an alternate title: "Opinions on something I don't know much about yet."


This is how I felt: http://imgur.com/1FFB0.jpg


My heart bleeds for you . Its really does. Writing boilerplate code -- oh the horror !

And yet an evil part of my brain would like to subject you to annotations and spring config xml files. But that can wait till you Python lovers grow up and get a real job !!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: