You are hereBlogs / marv's blog / Python Coolness 2: Tips and Tricks
Python Coolness 2: Tips and Tricks
Welcome back Pythoneers! Last time we learned the underlying concepts of the Python programming language and runtime environment. In this second part, I would like to show you some of the Python tricks, that make this programming language so special. I will also briefly highlight some of the areas, which prove to be more difficult or dangerous than in other common languages, such as Java and C++. After this tutorial you will be able to write lines of code that will definitely impress your fellow geeks.
So, let's get started. Recall the tuple type we learned about last time. Let's do a few things with tuples to learn what they can and can't do:
# Lets make some tuples point = (3.0, 2.0) # We can mix types client = ("marv", "male", 27, 1.80) # We can omit the parentheses in non-ambiguous cases four = "four", 4, 4.0 # We can access tuples using brackets client[0] > 'marv' # Trick: Access the last elements with negative values client[-1] > 1.8 client[-2] > 27 # Trick: We can access slices client[1:3] > ('male', 27) client[:2] > ('marv', 'male') client[2:] > (27, 1.8) # Concatenation works with '+' client + point > ('marv', 'male', 27, 1.8, 3.0, 2.0) # We can check if an element is in a tuple with 'in' 'male' in client > True # But: Tuples are IMMUTABLE point[0] = 4.0 > TypeError: 'tuple' object does not support item assignment
It is best you experiment more with tuples, so that you get a feel for them. So far, we have always used tuples on the right side of assignments. One great trick in Python is that you can use tuples on the left side. For instance, swapping values can be done in one step:
# Assign some values x = 3.0 y = 5.0 # Swap x,y = y,x
Neat, huh? Using this technique we could have also done the two x and y assignments at the beginning in a single line.
Now let's move on to lists. Basically, most of what can be said for tuples, applies to lists, and vice-versa. However, lists are highly mutable. We cannot only change values at certain indexes, but also add and remove values at will. Let's have some fun with lists:
# Create lists with brackets sentence = ['i', 'like', 'python'] # Concatenation works like before sentence = sentence + ['very'] # You can also append a non-list object sentence.append('much')
Okay, so nothing all too special yet. So let's look at a few other ways to construct lists. What if, for instance, we knew beforehand that our list has a specific length? Appending elements one by one is inefficient. For this, we can use the multiplication operator:
# Create a list with 10 zeros counts = [0] * 10 # Now we can set elements in that range counts[2] = 4
Often, we would like to create lists that enumerate over a certain range. This is especially useful for for loops:
# Create a list of numbers from 1 to 9 nums = range(1,10) # Loop over them for num in nums: print "I can count to %d!" % num
One of the most powerful features of Python are list comprehensions. They allow to create new lists from existing lists in a single line. Lets show how they work:
# Lets double every number in our nums list nums2 = [x * 2 for x in nums] # Lets get a list of all 2D positions in the range 0-4 positions = [(i,j) for i in range(0,5) for j in range(0,5)] # We could use this list to convert a 1D index # to a 2D index over the range 0-4,0-4 positions[8] > (1, 3) # We can also filter lists even = [x for x in nums if (x % 2) == 0] # Finally, as a more complex example, let's # find all prime numbers between 3 and 100 def multiples_of(x, max): return [x * i for i in range(2, max/x + 1)] # Get all numbers in range prime = range(3, 100) # Remove all multiples of 2...49 for i in range(2, 50): prime = [x for x in prime if not x in multiples_of(i, 100)]
Finally, I would also like to highlight the special relationship between lists and strings. Lets see what cool stuff we can do with the two:
# Strings work a lot like lists/tuples greeting = "hello" greeting[:4] > 'hell' "heaven" in greeting > False # Recall our sentence list sentence > ['i', 'like', 'python', 'very', 'much'] # String objects have a join() method " ".join(sentence) > 'i like python very much' # We can iterate through strings character by character ["(%s)" % c for c in "PYTHON"] > ['(P)', '(Y)', '(T)', '(H)', '(O)', '(N)'] # For instance, we can make a filter garbled = "t!hi(s se/nten?ce h=as so?me? p&robl?ems" alphabet = "abcdefghijklmnopqrstuvwxyz " # Output only alphabet characters "".join([c for c in garbled if c in alphabet]) > 'this sentence has some problems'
Enough with lists. Let's take a look at dictionaries. Dictionaries are a base type in python, and are very easy to use:
# Make a dictionary ages = { 'marv': 27, 'meck': 25, 'ph': 42 } # Access them like lists ages['marv'] > 27 # Iterating through keys: for name in ages: print "%s is %d years old!" % (name, ages[name]) # Or better: Using items() for name, age in ages.items(): print "%s is %d years old!" % (name, age)
Remember how everything in Python is a mapping object? Well, there are ways to convert these objects to a dictionary. One such function is locals(), which returns a dictionary with all variables at the local scope. Let's try it:
# Get all local variables, not starting with '_' myvars = [var for var in locals() if var[:1] != '_']
The value myvars should now contain all variables that we have created in this tutorial so far. One downside of Python, is that arguments passed to a function need to be type checked. Let's make a function that will simplify this process for us:
# This is our helper function to check types. What it # does will become clearer when we use it. def check_types(locals, desired): for name, type_needed in desired.items(): if not isinstance(locals[name], type_needed): raise ValueError("Wrong type for %s!" % name) # A test function def person_string(name, age): # Here comes the helper function check_types(locals(), { 'name': str, 'age': int }) # The actual function implementation return "%s is %d years old." % (name, age) # Test person_string("marv", 27) > 'marv is 27 years old.' # But: person_string("marv", 1.8) > ValueError: Wrong type for age!
New to Python are properties. Objective-C 2.0 has added these to the language as well, and they are a very powerful concept. Properties allow attribute access, that are actually handled by functions. Lets see how they can be used:
class Person(object): def __init__(self, first, last): self.first = first self.last = last # Accessors to full name def get_fullname(self): return "%s %s" % (self.first, self.last) def set_fullname(self, full): self.first, self.last = full.split() # Provide attribute like access using properties fullname = property(get_fullname, set_fullname) # Lets try it out marv = Person('Marius', 'Renn') marv.first > 'Marius' marv.last > 'Renn' marv.fullname > 'Marius Renn' marv.fullname = 'Marius Ju' marv.last 'Ju'
Although it may not seem like much at first, properties allow powerful patterns to be implemented. For instance, using an observer pattern, another object could track the changes to the attributes of a certain object. Property set-methods could then inform observers of any change.
WARNING: There is a common pitfall of properties. They ONLY work if your class is a subclass of object (which you should always do anyway). If your class does not inherit from any class, you will not get an error, but properties simply won't work.
One final thing I would like to show are lambda functions. These are constructs that allow you to quickly define a function, without having to actually declare it. Lambda functions have no name, and can therefore not be reused. Lets see how they work:
# Lets say we have this list numbers = range(1, 10) # We can get there sum simply by sum(numbers) > 45 # What if we wanted the product? There is the reduce function, which # applies a binary operation to all values in a list, starting from # the lowest index up to the highest. # Its signature is: reduce(FUNCTION, LIST) # So we could go ahead and do it this way: def mult(x, y): return x * y reduce(mult, numbers) > 362880 # Or we could simply use a lambda function reduce(lambda x,y: x * y, numbers) > 362880
Alright, that's all for this episode. I hope you learned a few things, and find that Python has a lot to offer. There are many things we have not covered, but the many tutorials on the web should help out here. Next time, we will program our first cool application, which should give you an idea of how Python can help you accomplish useful tasks with only a few lines of code.
- marv's blog
- Login to post comments