Home

Jul. 18th, 2007

happy

[info]dmitriid

Keep'em languages coming!

Past Friday I got myself acquainted to Python.

Different people view Python as "nothing to learn" or as "if only I had time to learn" or even as "very difficult to learn".

I had to learn it quick for a very simple reason. I have lots of photos taken at different resolutions. I need to resize them to different sizes (much like Flickr does), create several thumbnails of each image, upload them to a host (Amazon S3) and load information on uploaded images to a database.

The process must be automated, of course.

It all started when I convinced myself that Python Imaging Library is the best library to manipulate images. Indeed:

  1. import Image
  2.  
  3. im = Image.open('path/to/image')
  4. im.thumbnail((800, 800), Image.ANTIALIAS)
  5. im.save('path/to/image')


The line with im.thumbnail((800, 800), Image.ANTIALIAS) is absolute genius. If your image is, say, 1024х768px, then what you get in the end is not a skewed 800х800px, but a proportional 800x600px.

Combined with MySQLDb and Boto this yields a very easy solution to my task. However, that's not the point.

As it turns out, getting to know many languages (even superficially) may give you a huge head start in learning a new programming language. I've had an overview or, sometimes, more than an overview of such languages as Lisp, Haskell, Erlang... How does that help me with Python? Well, I got an imeddiate understanding of the following:

Note: I can bear no responsibility for Haskell codes in the examples :)


Tuples and destructuring assignment

A tuple is a fixed-length list. This list may contain elements that are very different in nature:
  1. # Python tuple
  2. (1, 2, 'hello')
  1. -- Haskell tuple
  2. (1, 2, "hello")
  1. %% Erlang tuple
  2. {1, 2, 'hello'}


Looks similar, doesn't it? :)

Let now get data out of our tuples:
  1. # Python
  2. # А will contain 1
  3. # В will contain 2
  4. # С will contain 'hello'
  5. A, B, C = (1, 2, 'hello')
  1. -- Haskell
  2. -- a will contain 1
  3. -- b will contain 2
  4. -- c will contain 'hello'
  5. (a, b, c) = (1, 2, "hello")
  1. %% Erlang
  2. %% А will contain 1
  3. %% В will contain 2
  4. %% С will contain 'hello'
  5. {A, B, C} = {1, 2, 'hello'}


Certainly, the principles of theses examples are very different. Haskell and Erlang use pattern matching that Python doesn't have. However, it looks very similar and is very easy to understand once you know the other examples. PHP, by the way, has a similar thing:
  1. // А will contain 1
  2. // В will contain 2
  3. // С will contain 'hello'
  4. list($A, $B, $C) = array(1, 2, 'hello')


This, of course, is very different and the inner workings are absolutely different :) One thing about this is quite peculiar, though. Once you get used to these sorts of destructuring assignments, you start using PHP's list and Python's tuples much more often. Because it's so convenient.

Named parameters

I once talked about named parameters. As it turns out, Pythons has them.
  1. # define a function
  2. def myfunc(param='', another_param=1)
  3.     print param, another_param
  4.  
  5.  
  6. # call the function
  7.  
  8. # will print hello 5
  9. myfunc(another_param=5, param='hello')
  10.  
  11. # will print hello 1
  12. myfunc(param='hello')
  13.  
  14. # will print 1
  15. myfunc()


Anonymous functions (lambdas)

  1. # Python
  2. # define a list
  3. li = [1, 2, 3, 5, 9, 10, 256, -3]
  4.  
  5. # get only evens out of the list
  6. li_even = filter(lambda item: item % 2 == 0, li)


Very similar to code in other languages:

  1. -- Haskell
  2. -- define a list
  3. li = [1, 2, 3, 5, 9, 10, 256, -3]
  4.  
  5. -- get only evens out of the list
  6. li_even = filter (\item -> (mod item 2) == 0) li
  1. %% Erlang
  2. %% define a list
  3. Li = [1, 2, 3, 5, 9, 10, 256, -3]
  4.  
  5. %% get only evens out of the list
  6. Li_even = lists:filter(fun(Item) -> Item rem 2 == 0 end, Li)


List comprehensions

Remember how we used to define lists in mathematics? For instance:
  1. S = [1, 2, 3, 4]
  2. M = {x | x in S, x even}


M is all x's where x belongs to S and x is even. Nice languages have ways to define lists in a very mathematical way. This is called list comprehensions. One downside to Python's comprehensions is the syntax. Here are previous examples rewritten to use list comprehensions instead of lambdas:

  1. # Python
  2. # define a list
  3. li = [1, 2, 3, 5, 9, 10, 256, -3]
  4.  
  5. # get only evens out of the list
  6. li_even = [x for x in li if x % 2 == 0]
  1. -- Haskell
  2. -- define a list
  3. li = [1, 2, 3, 5, 9, 10, 256, -3]
  4.  
  5. -- get only evens out of the list
  6. li_even = [x | x <- li, (mod x 2) == 0]
  1. %% Erlang
  2. %% define a list
  3. Li = [1, 2, 3, 5, 9, 10, 256, -3]
  4.  
  5. %% get only evens out of the list
  6. Li_even = [X || X <- Li, X rem 2 == 0]




Anyhow, thanks to other languages the new language (a more or less mainstream language, not K :)) ) is not just easy, it's extreamly easy and can be learned in, say, 15 minutes.



Update: Corrections to Haskell code. Thanks, [info]deni_ok