# Exploring The Lesser Known Features Of Python – Part II

As it is evident from the title, this is the second part in the Python exploration series. You can find the first part here. I have discussed a few lesser known but very useful features of Python. There were too many features, so I didn’t put everything in a single blog post. I will continue discussing more features in this post. I will keep adding more as and when I discover more things about Python.

In-place Value Swapping

When you want to swap two values, you create a temporary variable and then do the swapping. You can do it without using temporary variable too, but you have to do some operations. Python has a very direct way of doing this as shown below:

```>>> a = 10
>>> b = 5
>>> a, b
(10, 5)
>>> a, b = b, a
>>> a, b
(5, 10)```

The right-hand side of the assignment is an expression that creates a new tuple. The left-hand side of the assignment immediately unpacks that tuple to the names ‘a’ and ‘b’. After the assignment, the new tuple is unreferenced and marked for garbage collection, and the values bound to ‘a’ and ‘b’ would be swapped.

You might be inclined to think that this might use more memory than the traditional method, but the interesting thing is that it uses less memory. When you decompile the bytecode, you would see that the compiler does some optimizations. It sets up the variables and swaps the two top-most stack variables. It’s a pretty neat feature! You can read up more about how exactly the compiler optimizes it if you want.

Step Argument In Slice Operators

If you have used Python, you must have used slice operators a lot. You can use this to iterate using different increments. You can also use this to reverse the list. For example:

```a = [1,2,3,4,5]
>>> a[::2] # iterate over the whole list in 2-increments
[1,3,5]```

The special case x[::-1] is a useful idiom for ‘x reversed’.

```>>> a[::-1]
[5,4,3,2,1]```

Now you might wonder what advantage will this have over reversed() function. The problem with reversed() is that it returns an iterator, so if you want to preserve the type of the reversed sequence (tuple, string, list, unicode, other user types etc), you need an additional step to convert it back.

Regex Parse Tree

This is slightly more advanced and it’s regarding the regular expression (regex) in Python. You can get the Python regex parse tree to debug your regex. Regular expressions are a great feature of python, but debugging them can be a pain, and you can very easily get a regex wrong. The good thing is that Python can print the regex parse tree, by passing the flag “re.DEBUG” to re.compile.

If you are curious, run this code and check it out yourself:

```>>> import re
>>> re.compile("a+b*\s\w?", re.DEBUG)```

It will show a nice and clear form of this regex parse tree as shown below:

```max_repeat 0 65535
literal 97
max_repeat 0 65535
literal 98
in
category category_space
max_repeat 0 1
in
category category_word```

Once you understand what it means, you can easily spot the error.

Mutable Default Arguments

You should be careful in specifying the default arguments to a function. For example:

```>>> def myFunction(x=[]):
... x.append(3)
... print x
...
>>> myFunction()
[3]
>>> myFunction()
[3, 3]
>>> myFunction()
[3, 3, 3]```

Instead, you should use a sentinel value denoting “not given” and replace with the mutable you would like as default:

```>>> def myFunction(x=None):
... if x is None:
... x = []
... x.append(3)
... print x
>>> myFunction()
[3]
>>> myFunction()
[3]```

Decorators

In the general sense, a decorator is the name used for a software design pattern. Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.

A decorator with respect to Python is a little different. A Python decorator is a specific change to the Python syntax that allows us to more conveniently alter functions and methods. This not only supports more readable applications, but also has other uses as well. Decorators allow us to wrap a function or method in another function that can add functionality, modify arguments or results, etc. You write decorators one line above the function definition, beginning with an “at” sign (@).

Consider the example below. It shows a ‘printLine’ decorator that prints the decorated function’s arguments before calling it:

```def printLine(function):
def wrapper(*args, **kwargs):
print 'Arguments:', args, kwargs
return function(*args, **kwargs)
return wrapper

@printLine
def write(text):
print text

>>> write('Hello')
Arguments: ('Hello',) {}
Hello```

————————————————————————————————-