Python: Tips and Tricks

As you may have noticed, I have been messing around with python quite a bit lately. I remember trying it out back in college and using it on few small projects and then abandoning it for a while. Then I started working with Google App engine (back when it was Python only) and I got sucked into it once again. Since then it has become one of my go-to languages. In fact I’m amazed how the language grew up and matured since I first heard about it. So I figured I might as well devote a post to neat little tricks and quirks of this language.

IDLE Shell:

If you are going to be using Python, you should definitely check out IDLE. This IDE is bundled with most Windows python binaries, and you can get it as a separate package under linux. The editor itself is very basic, and you are probably better off using Vim or Emacs instead. It’s killer feature however is the neat python shell:

The IDLE Shell

It does everything a regular interactive python shell would do, but it offers a number of improvements such as syntax highlighting and easier code editing. Basically when you start typing in a block of code such as a function or a conditional IDLE evaluates it only after you are done – not line by line like the regular shell. This allows you to use the up arrow and for example fix the previous line in the block before the whole thing is evaluated. Also since the shell runs inside a text-editor like environment, it makes it much easier to copy and paste lines of code between you text editor and your shell.

Whenever you are using IDLE keep these things in mind:

  • Alt+P – previous history command
  • Alt+N – next history command
  • Put cursor on any line + hit Enter – copies the line down

It’s a great little tool. Use it.

Enumerate

Python does not actually have a traditional for loop. It has a foreach loop, but that works because most of the built in data structures in the language can be iterated over. If you need a traditional indexed loop, you just fudge it by doing something like this:

for i in xrange(10):
    print i

If you want to iterate over a list, you just do it. But what if you want to iterate over a list, but also keep track of the index of each element? Well, you could do something like this:

>>> foo = ('a', 'b', 'c')
>>> for i in xrange(len(foo)):
	print i, foo[i]
 
0 a
1 b
2 c

This is however not very “pythonic” and can be done much cleaner using the enumerate function. Observe:

>>> for i,j in enumerate(foo):
	print i,j
 
0 a
1 b
2 c

Same result, cleaner code. This function is there because the scenario in which you iterate over a list, while maintaining an index number is incredibly common.

Any and All

Here is another very common scenario: check if any element of the list is true. Or, better yet, check if all of them are true. There are two functions out there that do just that. Any returns true if at least one element in the list is true. All returns if all are true.

>>> any(i>5 for i in xrange(10))
True
 
>>> all(i>5 for i in xrange(10))
False

This will usually save you a loop or two.

Putting if and else into lambda functions

Lambdas are great, but sadly are much more limited than closures. Essentially they need to be one-liner expressions that evaluate to something. You can’t for example stick a traditional if/else block inside of a lambda. It just does not work, syntax wise. But you can do something like this:

>>> bar = range(5)
>>> map(lambda f: True if f>3 else False, bar)
[False, False, False, False, True]

This is the alternate syntax of if/else block that turns it into one liner. You put the results on opposite ends, and stick the test inside if/else keywords as shown above. This syntax has many applications but I find it’s greatest impact is on lambda functions.

Default Values

Here is something you should watch for in your code. Default values are only evaluated once when the function is first created. Observe:

>>> def t(a, b=[]):
	b.append(a)
	print b
 
>>> t(1)
[1]
>>> t(2)
[1, 2]
>>> t(3)
[1, 2, 3]

The function above takes two arguments: a value and a list, and then appends that argument to that list. If no list is passed as an argument, it ought to use an empty one. Only that it does not. The optional blank list is actually initialized once when the function is called without the second argument for the first time. Subsequent calls will reuse that same list – which is probably not the intended effect of that code.

Decorators

A fairly recent addition to python are decorators – or as I call them wrap-around functions function. Let me briefly explain them for you. For example lets take these two functions:

>>> def foo(func):
	return lambda: func() + 1
 
>>> def bar():
	return 1

The first one takes a function func as an argument. It returns another function which will run func and add 1 to its result. The second one on the other hand always returns 1. What will happen when we do this:

>>> bar = foo(bar)

When you call bar, it will now return 2:

>>> bar()
2

Why? Because the function foo wraps around it and modifies the result every time. Python nowadays contains syntatic sugar that makes creating these wrap-around functions cleaner and easier. I can redefine our function bar like this:

>>> @foo
def bar():
	return 1
 
>>> bar()
2

Putting @foo above the function definition is equivalent to the bar=foo(bar) line. Decorators are a great way to attach additional functionality to certain functions or methods. For example, they are used internally to implement:

Static and Class Methods

Unlike many other languages Python does not have special scope keywords, so you can’t really declare a method as static. But you can fudge it using decorators. In fact they were introduced mostly for this very purpose. Observe:

class Foo:
   @classmethod
   def a_class_method(self):
      print "OH HAI THAR! I'm " + self
 
   @staticmethod
   def a_static_method():
      print "Some stuff"

Class methods know which class they belong to – they take the class reference as the first argument. Static methods do no such thing – they do not take an argument.

Another neat use for decorator are:

Properties

By default all the members of a class are public. You can create getters or setters for private variables, but they can be accessed directly at any time. You can sort of hide them if you precede their names with double underscore – but that only mangles their name, and does not really provide total encapsulation. If you want more control you can utilize the @property decorator. Essentially you just declare your getter and setter methods like this:

class Foo(object):
   def __init__(self):
      self.__x = None
 
   @property
   def x(self):
      return self.__x
 
   @x.setter
   def x(self, value):
      if value <= 10:
            self.__x = value
      else:
            self.__x = 10

From now on, anyone trying to access the variable x, will be forced to go through these methods. It works exactly like properties in C# for example:

>>> a = Foo()
>>> a.x = 15
>>> a.x
10

The example above does not show this, but the getter and setter methods can be as complex, and include as much code as you want to. So you can implement input validation or format the output in a certain way, that is independent of the internal data type of the member.

As usual, I’m putting these things here mostly for my own reference. This way I can find these things in a few months after I completely forgot about them. But I found that frequently other people find these posts just as useful. So there you go.

This entry was posted in programming and tagged . Bookmark the permalink.



2 Responses to Python: Tips and Tricks

  1. Robert UNITED STATES Google Chrome Linux says:

    You might want to check out DreamPie, it’s a nice graphical python shell i stumbled upon a while ago.

    Reply  |  Quote
  2. John Roach TURKEY Google Chrome Linux says:

    Great python post! Even I learned a few tricks from this post. Thank you. :)

    Reply  |  Quote

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>