AssignmentStatement ::= Variable = Expression
To evaluate an AssignmentStatement, Python evaluates the Expression and places the value in the place named Variable. (Just like the Scheme evaluation rule for set!). The only difference is if there is not already a place named Variable, Python will create a new place as a result of the assignment statement. Hence, the Python statement x = 1 will act like (define x 1) if there is no place already named x, and like (set! x 1) if there is already a place named x.
An expression in Python is similar to an expression in Scheme — it is a code fragment that evaluates to a value. In Python, expressions use infix notation. The operator is placed between the operands (except for function calls, described below). Python supports most of the standard arithmetic operators. Here are some examples:
Scheme | Python |
---|---|
(define four 4) (define two (/ four 2)) (define bigger (< (* four four) 17) (printf "four: ~a two: ~a bigger: ~a" four two bigger) four: 4 two: 2 bigger #t |
four = 4 two = four / 2 bigger = (four * four) < 17 print "four: %d two: %d bigger: %d" % (four, two, bigger) four: 4 two: 2 bigger: 1 |
The parentheses in the assignment to bigger are necessary for grouping oprations. Without them it would mean (* four (< four 17)) instead of (< (* four four) 17).
Python uses 1 to mean true. Python considers the empty string, 0, and the empty list to be false, and (almost) everything else true.
The print procedure takes a string as input followed by a % and a list of values (in parentheses). The values are matched to the % codes in the string. Different % codes are used for printing different types of values. Here, %d is used to print an integer.
Applying Functions
In Python, we apply a function to operands by following the name of the function with a comma-separated list of arguments surrounded by parentheses:ApplicationStatement ::= Name ( Arguments )So, Proc (Arguments) in Python is similar to (Proc Arguments) in Scheme (except there are no commas between the arguments in Scheme).
Arguments ::=
Arguments ::= MoreArguments
MoreArguments ::= Argument ,MoreArguments
MoreArguments ::= Argument
Argument ::= Expression
Python only has a few primitive functions, but a very extensive standard library.
Defining Functions
Defining a procedure in Python is similar to in Scheme, except:- instead of using lambda, you list the parameters after the function name
- instead of just evaluating to a value, you must use return to explicitly evaluate to a result
FunctionDefinition ::= def Name ( Parameters ): <newline> StatementsFor example,
Parameters ::=
Parameters ::= MoreParameters
MoreParameters Parameter ,MoreParameters
MoreParameters ::= Parameter
Parameter ::= Variable
Scheme | Python |
---|---|
(define square (lambda (x) (* x x))) (define quadratic (lambda (a b c x) (+ (* a (square x)) (* b x) c))) (display (quadratic 2 3 7 4)) 51 |
def square (x): return x * x def quadratic (a, b, c, x): return a * square (x) + b * x + c print quadratic (2,3,7,4) 51 |
Note that unlike Scheme, where the procedure body is an expression and the value of an application is the value of that expression (evaluated in the new environment with the parameters bound), in Python, the procedure body is a list of Statements. The special statement,
ReturnStatement ::= return Expressionis used to return a value from a procedure. When execution encounters a return statement, the Expression is evaluated and returned to the caller.
Python also provides a form lambda for making procedures the way you would in Scheme using lambda:
Expression ::= lambda Parameters : ExpressionThe parameters are defined as above, and the body is the one expression (a return before the expression is implied). For example, (lambda (a b) (+ a b)) would be lambda a, b: a + b. Here's an example:
def makeAdder (a): return lambda b: a + b add5 = makeAdder (5) print "Adding: " + str(add5(2))
Adding: 7
Note that here we concatenate the string "Adding: " with str(adder(2,2)); str converts the output of adder(2,2) to a string.Python does not evaluate applications the same way as Scheme, however. In particular, Python does not create a chain of frames for evaluation purposes. Instead, there are only two namespaces (Pythonspeak for frames): the global namespace and the local namespace.
Control Statements
Python also provides several statements similar to Scheme special forms. Two useful ones are if and while which are described below.If
The if statement is similar to Scheme's if special form:Statement ::= if (Expression): <newline> Statementsis equivalent to (if Expression (begin Statements)).
Python also supports alternative clauses but uses else to distinguish them:
Statement ::= if (Expression) :is equivalent to (if Expression (begin Statements1) (begin Statements2)).
Statements1
else :
Statements2
While
The while statement repeats a sequence of statements as long as the test expression is true:Statement ::= while (Expression):The indentation of the statements determines the statements that are looped.
Statements
Here is an example that will print out the first 10 Fibonacci numbers:
i = 1; a = 1; b = 1; while (i <= 10): print "Fibonacci %s = %s" % (i,b); next = a + b; a = b; b = next; i = i + 1; print "Done."
Types
Like Scheme, Python has latent (invisible) types that are checked dynamically. The four types you will find most useful are numbers, strings, lists, and dictionaries.
Numbers
Python treats numbers like Scheme, except it does not do exact arithmetic. Instead of using fractions, everything is treated as either an integer or a floating point number. Here are some examples:
Scheme | Python |
---|---|
(define four 4) (define pi 3.14159) (define half 1/2) |
four = 4 pi = 3.14159 nothalf = 1/2 (evaluates to 0) half = 1.0/2.0 (evaluates to .5) |
What happened when we defined nothalf?
Unlike Scheme, Python makes a distinction between integer math and floating point math. This normally isn't that important; when we do math between the same types, the result is the same type, and when we do math with a floating point number and an integer, the type returned is a floating point number. However, the result of division of an integer by another integer is not necessarily an integer -- Python will silently discard the fractional part of the answer. By writing the operands with decimal points, we ensure that the operation will return a floating point number. This problem only rarely occurs, but you should always be aware of it when searching for bugs.
Strings
Python treats strings like Scheme: they need quotation marks. You can use single quotes ('), double quoteS ("), or triple quotes ("""). However, there is a very important difference between triple quotes and other quotes; when you use triple quotes you can break lines in the string, but when you use single or double quotes you can not.You can concatenate (run together) two strings by using the plus sign (+):
name = "Spot"If you want a literal quote to appear in a string you print, use \":
print "See " + name + " run."
print "My name is \"Spot\"."The triple quote, """ is an easy way to print large chunks of text that can include double quotes and new lines. For example,
print """ "I find that the harder I work, the more luck I seem to have." --- Thomas Jefferson """will print out
"I find that the harder I work, the more luck I seem to have."
--- Thomas Jefferson
Lists (and Tuples)
Python has its own version of lists; although these have many things in common with Scheme lists, it's best to think of them as a different data type.The biggest difference between a Scheme list and a Python list is that elements in Python lists are can be accessed directly. This means that we can access any element of the list if we know it's number; we had to write our own function in Scheme to get this functionality.
Scheme | Python |
---|---|
> (define lst (list 10 20 30)) > (car lst) 10 > (car (cdr (cdr lst))) 30 |
lst = [10, 20, 30] print lst[0] 10 print lst[2]30 |
Indices in Python are much more powerful than that, however. We can "slice" lists to only look at a subset of the list data.
(Note that decimal numbers are not exact — we put 302.234 in the list, but the printed value is 302.23399999999998.)lst = [10, 20, 40, "string", 302.234]
print lst[0:2]
[10, 20]
print lst[:3]
[10, 20, 40]
print lst[3:]
['string', 302.23399999999998]
Finally, if we want to iterate over an entire list, we use the for statement:
Statement ::= for VaribleList in ExpressionList : StatementsFor example,
def sum (lst): total = 0 for el in lst: total = total + el return total print sum([1, 2, 3, 4])
10
Dictionaries
Python also has "dictionaries", referred to as a "hash tables" or "lookup tables" in some other languages.A dictionary is a list of (key, value) pairs. In Python, the key can be any "immutable" object (tuples, strings, numbers), and the value can be any Python object. We can initialize a dictionary using the initialization expression:
DictionaryInitializationStatment ::= Variable = { InitializationExpressions }
InitializationExpressions ::=
InitializationExpressions ::= InitializationExpression, InitializationExpressions
InitializationExpression ::= Expression : Expression
The expression before the : is the key, and the following expression is the associated value.
We can set the value associated with a key using a set statement:
SetStatement ::= Expression [ Expression ] = ExpressionWe get the value associated with a key using:
FetchExpression ::= Expression [ Expression ]The first expression in a fetch expression must evaluate to a dictionary.
Here are some examples:
yellow = { 'red': 255, 'green': 255, 'blue': 0 } print '(%s, %s, %s)' % (yellow['red'], yellow['green'], yellow['blue'])(255, 255, 0)
yellow['red'] = 230 print '(%s, %s, %s)' % (yellow['red'], yellow['green'], yellow['blue'])(230, 255, 0)
Of course, we can put arrays in arrays, just like we can make lists of lists in Scheme. To do something to everything in the array, we first have to use the built-in "keys" method of the dictionary. For example, to reset yellow, we would do:
for key in yellow.keys():There are several other useful operators for dictionaries:
yellow[key] = 0
- expr in dictionary — evaluates to true if there is a key in the dictionary that matches the value of expr
Classes
In Scheme, we defined objects by explicitly packaging procedures and state. Python provides classes as a way to package procedures and state. We will only scratch the surface of Python's object-oriented features here, but it is an integral part of the language.
ClassDefinition ::= class Name:
FunctionDefinitions
These function definitions will form the "methods" of the class. There are lots of special methods, and we can also create our own. The only special method we'll worry about now is the __init__ method that is used when we create an instance of an object. The __init__ method is similar to the make-class methods from Problem Set 6.
Here's an example:
Scheme | Python |
---|---|
(define (make-object name) (lambda (message) (case message ((class) (lambda (self) 'object)) ((object?) (lambda (self) #t)) ((name) (lambda (self) name)) ((say) (lambda (self list-of-stuff) (if (not (null? list-of-stuff)) (display-message list-of-stuff)) 'nuf-said)) ((install) (lambda (self . args) 'installed)) (else no-method)))) |
class my_object: def __init__(self, name): self._name = name def is_object(self): return True def whatclass(self): return type(self) def name(self): return self._name def say(self, lst): for x in lst: print x def install(self, args): print "Installed" |
Although the differences between the two languages prevent a direct translation (for example, object and class are both reserved words in Python, and we can't have both a data item and a member function titled "name"), it is easy to see the similarities here. We don't have to use application to create a new frame in Python; the language takes care of that for us. The variable _name introduced in __init__ will be stored in a place accessible only to this object. self._name refers to the _name variable inside the object self; self is passed into any method of an object (we'll see how this works below.)
In the first line, we create a new my_object, passing it the value "bob" which will be stored as the _name value; this calls the classes __init__ method. Now, whenever we type obj.method(args), the member function of my_object is called with the first argument obj and the other arguments to the function appended in a frame where this objects variables are defined.obj = my_object("bob")
obj.name()
"Bob"
obj.is_object()
True
obj.say(["hello, world"])
hello, world
Python provides a convenient mechanism for inheritance:
ClassDefinition ::= class SubClassName ( SuperClassName ) :creates a new class named SubClassName that inherits from SuperClassName. Here's an example from PS6:
FunctionDefinitions
Scheme | Python |
---|---|
(define (make-lecturer name) (let ((super (make-object name))) (lambda (message) (if (eq? message 'lecture) (lambda (self stuff) (ask self 'say stuff) (ask self 'say (list "you should be taking notes"))) (get-method super message))))) |
class lecturer (my_object): def lecture(self, stuff): self.say (stuff) print "you should be taking notes" |
Because of Python's built in support for classes, object-oriented programs in Python are shorter and more elegant than object-oriented programs in Scheme.
Interacting with Web Requests
Producing Output
When a client browser requests a cgi page that is a python program, the web server runs the Python interpreter on that page and sends the output back to the client. The output is everything the page prints, so all you have to do in a Python program to send content back to the client is use print.The first line of the CGI file should be:
#!/uva/bin/pythonThis tells the web server that the rest of the file is a Python program that should be executed to produce the output page.
In order for the output to be interpreted as HTML, we need to print the content type at the beginning of the output:
print "Content-type:text/html\n"The \n prints a new line.
Getting Input
This assigns to form a dictionary of form values. For every form element with a name="Name" parameter in your HTML form, form will have a field with the name Name and assign it whatever data the user entered. We can access this with form["Name"].getvalue(). This extra getvalue() is required as opposed to a regular dictionary because of how CGI processes the form.
For the example form:
The file listed as ACTION= in the form will process the submitted form. Here's what formproc.cgi contains:<FORM METHOD="POST" ACTION="formproc.cgi">
First name: <INPUT TYPE="TEXT" NAME="FirstName"><BR>
Last name: <INPUT TYPE="TEXT" NAME="LastName"><BR>
Comments:<BR>
<TEXTAREA ROWS="3" NAME="UserComments"></TEXTAREA><BR>
<INPUT TYPE="SUBMIT"><INPUT TYPE="RESET">
</FORM>
#!/uva/bin/python import cgi print "Content-type:text/html\n" print "<html><head><title>Form Response</title></head>\n" print "<body>\n" form = cgi.FieldStorage() print "Thank you for your information!" print "<BR>" print "The keys are: " print form.keys () print "<p>" print "First name: " + form['FirstName'].value + "<br>" print "Last name: " + form['LastName'].value + "<br>" print "Comments: " + form['UserComments'].value + "<br>" print "</body></html>\n"
You can try it here:
|
Using SQL
Before reading this section, read the SQL Guide.Python provides procedures for interacting with a database using SQL. You can call these procedures like any other Python procedure. The Python evaluator will send the appropriate commands to the SQL database.
Before using any SQL commands, you'll want to connect to the database server and open a database. To tell Python we're going to be using a MySQL database, we begin the script with
import MySQLdb
Now you can connect to the database with your username and the password you created before, for example:
server = "dbm1.itc.virginia.edu"
username = "dee2b"
password = "quist"
dbName = "dee2b_presidents"
db=MySQLdb.connect(server, username, password, dbName)
In particular, dbm1.itc.virginia.edu is the hostname of ITC's database, username and password are those used to create your account, and dbName is the name of the database you created.
Now that we have a connection to the database we'll need a cursor to actually operate on it. Basically a cursor is just a way of keeping track of where you are in a table or result set. Getting a cursor from the database is simple:
cursor = db.cursor()
Now that we have a cursor to the database, we can execute queries, for instance:
college = "William and Mary" cursor.execute("""Select lastname, firstname from presidents where college=%s order by lastname""", (college,))
That last part, (college,) probably looks a little funny: this is simply because Python's database interface requires any parameters as a sequence. In general, if you know what you're looking for, you could insert it directly, for instance:
cursor.execute("""Select lastname, firstname from presidents where college='William and Mary'""")
Using %s lets us figure out something to look for based on a variable (for instance, a form field) rather than having to hard-code it. Now that we've executed the database query, if we did a SELECT statement, there are a few things we can do with the cursor:
- cursor.fetchone() - This gives the result that the cursor is currently pointing at, and then advances to the next one.
- cursor.fetchall() - This gets all of the results from the cursor to the end of the set and gives them back to you as a tuple of tuples.
db.commit()
At the end of your program, you can close the database connection with
db.close()
It's important to make sure you've committed the changes before closing, because otherwise the Python database interface will assume you didn't mean to make the changes and will perform a rollback - essentially undoing every change since the last commit.
Credits: This guide was created by David Faulkner, Dan Upton, and David Evans for CS150 Fall 2005. It was revised for CS 150 in Spring 2009 by Westley Weimer. |
cs150: Computer Science
from Ada and Euclid to Quantum Computing and the World Wide Web
Instructor
Westley Weimer
Teaching Assistants
Zak Fry
Paul DiOrio
Rachel Lathbury
Email Address
cs150-staff@cs.virginia.edu
Mondays and Wednesdays, 3:30-4:45pm in MEC 341
Wednesdays, 7:00-8:00pm and 8:00-9:00pm in OLS 001
(Small Hall Lab)
Monday 5:00-6:00 (Zak)
Tuesday 3:15-4:15 (Rachel)
Thursday 5:00-6:00 (Paul)
Sunday 3:00-4:00 (on request)
(Small Hall Lab)
Monday 2:00-3:00 (Rachel)
Tuesday 11:00-12:00 (Wes in Olsson 219)
Tuesday 3:00-4:00 (Zak)
Wednesday 1:00-2:00 (Paul)