I spent this weekend reading Learning Python (Second Edition for Python 2.3!) by Mark Lutz. Python is my favorite programming language, but my experience with it has been mostly anecdotal; I come up with my own solutions and functions and I Google whatever I do not know. I decided to spend a couple of days with this incredibly out-of-date book to formalize my knowledge of the base Python language. It was fairly easy reading because I already had experience with about 80% of the constructs discussed. But it was fun to learn some things that I have not used, and some things that I did not even know existed. I want to share some of these gems here. Pardon me if all of this stuff is obvious to you ;-).
Populating a String with a Dictionary
>> data = {}
>> data['first_name'] = "Ryan"
>> data['age'] = 21 #some programming humor
>> print "Hello, my name is %(first_name)s and I am %(age)d years old." % data
Hello, my name is Ryan and I am 21 years old.
Notice that we can also put a function after the last % sign above, as long as the function returns a dictionary.
The s and the d after the dictionary keys are the usual format specifiers (s for string and d for a number).
This gem is important to me because I use dictionaries containing tons of data and need to reformat it! This is what I used to have to do:
>> print "Hello, my name is %s and I am %d years old." % (data['first_name'], data['age'])
Some More on Printing to Streams
By default, separating variables by a comma will produce a space between the outputted variables
>> x = 3
>> y = 2
>> print x, y
3 2
Usually print automatically inserts a newline at the end of the output. We can suppress it by using a dangling comma. This is more useful when printing to another stream such as a file.
>>> x= 2
>>> y = 3
>>> out = open("temp.txt", "w")
>>> print >> out, x,
>>> print >> out, y,
>>> out.close()
The file then contains the line
2 3
Do it, Or Else…or Not
A for or while loop can have an else, to perform actions when control leaves the loop without encountering a break. Personally, I think done, when-complete or something similar would have been better than else.
Consider the example of searching a list for a value.
>>> names = ["Sarah", "Nick", "Sam", "Chloe"]
>>> for name in names:
... if name == "Ryan":
... break
... else:
... print "Not found!"
...
Not found!
Global only Matters for Assignment
If we define a variable outside any class or a function it is global. We can access the variable in any enclosing functions, but we cannot modify it. This is new to me. What I used to do was this:
>>> x = 3
>>> def f():
... global x
... print x
...
>>> f()
3
when all I really need is:
>>> x = 3
>>> def f():
... print x
...
>>> f()
3
However, we do need the statement global x if we modify the variable.
Class Properties
Class properties simplify the creation of getters and setters…sort of. Of course, if we define a class attribute outside of a class method, we can access it without a getter or setter:
>>> class MyClass:
... myvar = 2
...
>>> a = MyClass()
>>> a.myvar
2
>>> a.myvar = 3
>>> a.myvar
3
But if we want to be more careful, we do not define the variable in such a way. Instead, we can define it in a class method then write our getter and setter methods. By creating a property, we essentially overload the = operator and allow access to the variable as if it were defined as above. Using the property constructor, we tell what methods to use as the getter and setter. In other words, we do not need to use the getter and setter methods. After typing all of that, this seems trivial…
>>> class MyClass:
... def __init__(self):
... self.myvar = 2
... def getmyvar(self):
... return self.myvar
... def setmyvar(self, val):
... self.myvar = val
... myvar = property(getmyvar, setmyvar, None, None)
...
>>> h = MyClass()
>>> h.myvar
2
>>> h.myvar = 3
>>> h.myvar
3
>>>
Finally, Exceptions
I use exceptions a lot, but there are some constructs I just now read about, particularly, finally. Ha ha.
try/finally
Suppose, we want to run some code in a try block. We know that we want a particular code block to run whether or not an exception occurs. It is assumed that the exception is caught by the caller (or higher caller). The try block will run regardless and so will the finally block. This does not leverage the power of exceptions, unless the caller catches the exception.
Catch Multiple Exceptions
Our code can catch multiple exceptions by enclosing the exception types in a tuple. We can also get data associated with the exception. I have used this data several times, but always forget the syntax.
>>> try:
... html = urllib2.urlopen(url).read()
... except (urllib2.HTTPError, httplib.BadStatusLine), e:
... print "An error %s occurred. Let's sleep it off." % str(e.code)
... time.sleep(1)
try/except/else
Our code in the try block is executed and one of two things happen: an exception occurs, or not. If an exception occurs, hopefully we catch it using except. If we do not, we hope the caller catches it. If no exception occurs, the code within else is run.
try:
html = urllib2.urlopen(url).read()
except (urllib2.HTTPError, httplib.BadStatusLine):
print "Website is down or something."
time.sleep(1)
except:
print "Something else tragic happened."
else:
parse_html(html)
try/else
Unlike the try/finally construct, the else block only runs if the code in the try block runs successfully. This allows us to avoid using boolean flags to test for success!
Although I learned a lot from the second edition, I think it is time to buy the fourth edition…
Leave a Reply