Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Sep 18th, 2005, 10:53 AM   #1
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Advanced Python Tricks

Python is a language that is often underestimated, and often underused. Beneath its deceptively simple exterior, Python has some very powerful features that you may not be aware of. This post will introduce you to some of these less well known corners of the Python programming language.

(If you're a Python guru, feel free to ignore this )

Properties

Properties gives Python all the advantages of getter and setter functions, along with the convenience of normal object variables. To show you what I mean, consider a class ExamResult with a variable called score. Like most exam results, the score is a percentage, and can be anything from 0 to 100. A score above 100, or below 0, is clearly invalid.

Traditionally, we might write a class with some getter and setter functions:

class ExamResult:
   def __init__(self, score = 0):
      self.set_score(score)

   def get_score(self):
      return self.__score

   def set_score(self, score):
      if (score < 0) or (score > 100):
         raise ValueError
      else:
         self.__score = score
         
result = ExamResult()
try:
   result.set_score(110)
except ValueError:
   print "Cannot score more than 100%"
   
result.set_score(79)
print "Exam score: %d%%" % result.get_score()
But with class properties, we can go a step further:

class ExamResult(object):
   def __init__(self, score = 0):
      self.set_score(score)

   def get_score(self):
      return self.__score

   def set_score(self, score):
      if (score < 0) or (score > 100):
         raise ValueError
      else:
         self.__score = score
         
   score = property(get_score, set_score)
   
result = ExamResult()
try:
   result.score = 110
except ValueError:
   print "Cannot score more than 100%"

result.score = 79
print "Exam score: %d%%" % result.score

Higher Order Functions

Most functions take in and return variables and values. Higher order functions take in and return other functions. This is an important and powerful concept in programming; rather than manipulating data, you're manipulating code.

To demonstrate this, here's a simple higher-order addition function:

def add(x):
   def inc(y):
      return x + y
   return inc
This function takes a different approach to addition than you may be used to. Rather than return a number, add returns a function that increments a number by a certain amount. For instance, add(1) will return a function that increments a number by 1, whilst add(9) will return a function that increments a number by 9.

To use this function to add up two numbers, we call it twice over:
inc = add(1)
inc(10)      # returns 11
add(9)(5)    # returns 14
The ability to create functions on the fly is a very very powerful feature, and should not be underestimated.


Generators

All python programmers are familiar with for-loops, and their ability to iterate over a list. What some programmers may not know, is that you can also use generator functions.

For instance, take the humble range function, which returns a list of incremental numbers. This is useful enough in some cases, but less useful when used in a for-loop that will run for thousands of iterations:

for i in range(10000):
   # do something
This function is rather inefficient, as it generates a list of 10'000 numbers before it even begins the loop, using up a lot of memory and CPU time. So how can this be improved?

An easy way is to use a generator function and the yield keyword:

def quick_range(x):
   i = 0
   while i < x:
      yield i
      i += 1
      
for i in quick_range(10000):
   # do something
Due to the yield keyword, quick_range returns a generator object when called. This generator object has a function called next() that returns i each time it is called. When the loop ends, a StopIteration exception is thrown.

This generator function can be used in for loops in much the same way as a list is. It's also faster, since there is no need to allocate memory for a 10'000 member list.

Because iterating over large numbers is a common problem, Python supplies the xrange function, which is similar in nature to the quick_range function, as supplied above. Using xrange when dealing with large numbers can dramatically increase the efficiency of your program.


Assertions

Java programmers will (hopefully!) be familiar with assertions. Simply put, an assertion is a test that raises an AssertionError if the test fails. Assertions are a valuable debugging tool, as they prevent errors propagating through your software by catching them early.

Take this buggy code:

def get_year_from_user():
   year = raw_input("Enter your birth year: ")
   if (year == 2006):
      raise ValueError, "That year has not happened yet"
   return year

def get_age_from_year(year):
   age = 2005 - year
   return "You are either %d or %d years old" % (age, age - 1)

user_year = get_year_from_user()
print get_age_from_year(user_year)
If someone entered in "2007" as their birth year, no error would be raised, which is clearly not what we want to happen. But with an assertion in get_age_from_year, this error would be easily caught:

def get_age_from_year(year):
   age = 2005 - year
   assert age >= 0
   return "You are either %d or %d years old" % (age, age - 1)

Fun with lists

Python has some very powerful functionality for handling lists. Everyone knows about the "in" keyword when in a for-loop:

for i in range(10):
   pass
Slightly less well known is the use of the keyword to test if an object is
contained within a list:

if user_fruit in ['apple', 'banana', 'grapefruit']:
   print "Valid fruit"
List comprehensions are also extremely useful to know, as they are Python's way of manipulating lists. A simple list comprehension is detailed below, which creates a list of the first 10 square numbers.

[i * i for i in range(10)]
If statements can be used to filter the results. The code below creates a list of the even numbers from 1 to 10:

[i for i in range(10) if (i % 2) == 0]

Last edited by Arevos; Sep 18th, 2005 at 11:22 AM.
Arevos is offline   Reply With Quote
Old Sep 18th, 2005, 11:09 AM   #2
coldDeath
Expert Programmer
 
coldDeath's Avatar
 
Join Date: Aug 2005
Location: UK
Posts: 862
Rep Power: 4 coldDeath is on a distinguished road
Send a message via AIM to coldDeath Send a message via Yahoo to coldDeath
Nice article =) maybe it could be stickyed

It may get soem more python users among us

Another thing I would like to point out is the os module.

In Python there is a standard module called os. I believe that every function in it is multiplatform, but i will probably be corrected.

As you know in Windows a file path uses backslashes.
Example: \data_files\save_games\save1.dat

In Unix we use forward slash.
Example: /home/user_name/game/save_games/save1.dat

So if you wanted to load somethign from another folder, in another programming langauge, you would have to first check which operating system it is being run on, then use an if statement to choose wether to use / or \.

With the os module you can simply use the join() function.

#Platform independent!
import os
os.join("data","save_games")
__________________
Join us at #programmingforums @ irc.freenode.net!

My software never has bugs. It just develops random features.
coldDeath is offline   Reply With Quote
Old Sep 18th, 2005, 12:31 PM   #3
Ooble
I eat cake for breakfast.
 
Ooble's Avatar
 
Join Date: Jul 2004
Location: In my box.
Posts: 4,434
Rep Power: 9 Ooble is on a distinguished road
I think this thread is about language features, not specific libraries. Anyway, nice work Arevos. I'll be bookmarking this one.
__________________
Me :: You :: Them
Ooble is offline   Reply With Quote
Old Sep 18th, 2005, 1:15 PM   #4
Cerulean
Professional Programmer
 
Cerulean's Avatar
 
Join Date: Apr 2005
Location: London, England
Posts: 459
Rep Power: 4 Cerulean is on a distinguished road
But the standard library and Python's features go hand in hand.

Quote:
Originally Posted by Arevos
List comprehensions are also extremely useful to know, as they are Python's way of manipulating lists.
Well, they're a way of manipulating a list clearly and easily (on one line). Functional programming functions like map and filter did the job before, but were slower as they took a function as a parameter that was called each times, and function calls are costly over big sets of data. Here are two list comprehension snippets and their Python functional programming equivalent. Might help you if you're going over old code and don't know what they do
# Calls a function, passing each item in the list and returning the new list
map(str, [2, 3, 5, 1]) == [str(x) for x in [2, 3, 5, 1]] 
# Filters out items in a list based on whether or not the function the item is passed to returns True or False
filter(bool, [1, 0, 3, 1, 0]) == [x for x in [1, 0, 3, 1, 0] if bool(x)]
Another thing you may not know about is lambda. It is just a simple way to define a one-line function that takes parameters and does a single operation on them, returning the result. Only really useful when you're working on one line, e.g with map or something. For example:
def foo(x):
    return x == 2
# is the same as
foo = lambda x: x == 2
# but you can use lambda inline.
# e.g filter out every number in the list that isn't a 2
filter(lambda x: x == 2, [2, 1, 4, 2, 5, 3])
Cerulean is offline   Reply With Quote
Old Sep 18th, 2005, 4:01 PM   #5
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
lambdas are being talked being depreciated in Python, though, based on the thinking that they're not really needed.
Arevos is offline   Reply With Quote
Old Sep 18th, 2005, 5:36 PM   #6
Cerulean
Professional Programmer
 
Cerulean's Avatar
 
Join Date: Apr 2005
Location: London, England
Posts: 459
Rep Power: 4 Cerulean is on a distinguished road
Yeah, Guido really wants them out for Python 3.0. That's more than fine now that they've introduced list comps, though. I primarily put the examples there for people that may come to maintain code that uses them.
Cerulean is offline   Reply With Quote
Old Sep 18th, 2005, 6:14 PM   #7
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Quote:
Originally Posted by Cerulean
Yeah, Guido really wants them out for Python 3.0. That's more than fine now that they've introduced list comps, though. I primarily put the examples there for people that may come to maintain code that uses them.
Okay, good thinking
Arevos is offline   Reply With Quote
Old Sep 18th, 2005, 6:32 PM   #8
Dameon
Troll
 
Dameon's Avatar
 
Join Date: Apr 2005
Location: Texas
Posts: 732
Rep Power: 4 Dameon is on a distinguished road
Just as C# decides to put them in
__________________
MD5(sig) = bcef75433db02e9ad9bf81d6f7c5c270
Dameon is offline   Reply With Quote
Old Sep 19th, 2005, 2:28 PM   #9
Dietrich
Professional Programmer
 
Dietrich's Avatar
 
Join Date: Feb 2005
Posts: 434
Rep Power: 4 Dietrich is on a distinguished road
Smile

Quote:
Originally Posted by Cerulean
But the standard library and Python's features go hand in hand.


Well, they're a way of manipulating a list clearly and easily (on one line). Functional programming functions like map and filter did the job before, but were slower as they took a function as a parameter that was called each times, and function calls are costly over big sets of data. Here are two list comprehension snippets and their Python functional programming equivalent. Might help you if you're going over old code and don't know what they do
# Calls a function, passing each item in the list and returning the new list
map(str, [2, 3, 5, 1]) == [str(x) for x in [2, 3, 5, 1]] 
# Filters out items in a list based on whether or not the function the item is passed to returns True or False
filter(bool, [1, 0, 3, 1, 0]) == [x for x in [1, 0, 3, 1, 0] if bool(x)]
Another thing you may not know about is lambda. It is just a simple way to define a one-line function that takes parameters and does a single operation on them, returning the result. Only really useful when you're working on one line, e.g with map or something. For example:
def foo(x):
    return x == 2
# is the same as
foo = lambda x: x == 2
# but you can use lambda inline.
# e.g filter out every number in the list that isn't a 2
filter(lambda x: x == 2, [2, 1, 4, 2, 5, 3])
Using the timeit module, map() comes out the winner over its list comprehension equivalent by a nose.
__________________
I looked it up on the Intergnats!
Dietrich is offline   Reply With Quote
Old Sep 19th, 2005, 2:34 PM   #10
Dietrich
Professional Programmer
 
Dietrich's Avatar
 
Join Date: Feb 2005
Posts: 434
Rep Power: 4 Dietrich is on a distinguished road
Smile

Quote:
Originally Posted by Arevos
lambdas are being talked being depreciated in Python, though, based on the thinking that they're not really needed.
How would you replace lambda in dictionary usage?
# Python can do a switch/case like thingy using a dictionary and lambda
# basis for a nice calculator

def do_operation(op, a, b):
    """here a dictionary combined with the lambda inline function acts like switch/case"""
    return {'+': lambda: a + b,
            '-': lambda: a - b,
            '*': lambda: a * b,
            '/': lambda: a / b
           }[op]()

print do_operation('+', 2, 5)
__________________
I looked it up on the Intergnats!
Dietrich is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 11:50 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC