Python Lessons - Intro & Part 1
Intro
A friend of mine, who is studying Computer Science, asked me to help him learning a Programming Language. Students with no background in programming often learn Java as first language, which I find very hard to learn, with nearly no experience and knowledge of the concepts used in Java. My understanding of developing computer programs is, one need to learn the basic concepts of developing and with mastering one language, nearly every language can be understood and mastered. I decided to teach him Python, because Python is a widely used and grown Scripting Language, which covers object orientation, mostly clean syntax and readability. Readability is good for learning a language by looking at programs from others.
In several parts I will slowly cover the basics of Python. I don’t like guides, with no real world examples, implementing Fibonacci for the millions time. In the first parts we will build a small tool for monitoring/checking a Website. Later we will program something more complex, like a Web Crawler.
If anyone, from an English speaking country, like to lecture my text, feel free to send me corrections.
Requirements
- Basic knowledge of programming, I will not describe what a variable is for
- Linux, preferable based on Debian, like Ubuntu
- Working Python installation, >= Python 2.7, < Python 3.0
Developer Environment
To write Python programs I use a combination of tools, which make life more easy.
Editor
I use Sublime Text. It’s fast and light. There are tons of great plugins, written in Python. It can be tested for free, without registration, as long as you need to. The editor is Cross-platform, available for Linux, Mac OS X and Windows. I recommend using the plugins Package Control, which is for installing plugins easily and SublimeLint, installable via Package Control. SublimeLint checks your Python code (and more) for syntax and style guides. My basic settings for Sublime Text (Preferences -> Settings User) are the following.
{
"detect_indentation": false,
"draw_white_space": "all",
"find_selected_text": true,
"fold_buttons": false,
"font_options":
[
"subpixel_antialias"
],
"font_size": 14,
"highlight_line": true,
"ignored_packages":
[
"Vintage"
],
"rulers":
[
72,
79
],
"tab_size": 4,
"translate_tabs_to_spaces": true,
"trim_trailing_white_space_on_save": true,
"use_tab_stops": true
}
VirtualEnv
VirtualENV is a fantastic Python tool to isolate dedicated environments from the system. It creates an environment that has its own installation directories, that doesn’t share libraries with other VirtualENV environments and by default even not with the Python system installation. Inside a VirtualENV you can do no harm. Install as much Packages as you like, screw around, if something broke, delete the VirtualENV and create a fresh one.
Installation
cd ~/Downloads/
wget -O pypa-virtualenv.tar.gz https://github.com/pypa/virtualenv/tarball/master
tar xf pypa-virtualenv.tar.gz
cd pypa-virtualenv-*/
sudo python setup.py install
Create your first VirtualENV and activate it
virtualenv myenv
cd myenv
source bin/activate
Now you are inside a VirtualENV. Leave the VirtualENV with the deactivate
command. In a VirtualENV one has access to several programs. Of course, the Python interpreter python
. Also pip
. PIP is a Python Package Manager, which can manage packages from the Python Package Index, PyPI. PIP will be used later.
Hello World
Our first program will be the famous “Hello World” program.
#! python
if __name__ == '__main__':
print 'Hello World!'
Create a VirtualENV, active it, open your favorite editor, paste the code from above and execute the created Python file with the Python interpreter, python hello_world.py
. The string “Hello World!” will be printed.
- Line 1: The Shebang, explained here. Must have in each Python script, which will be called with
python
! Good style and very useful with VirtualENVs. - Line 3: I will explain this strange if statement later. For now just accept it, that it is good style to start your main program logic inside this if statement.
- Line 4: The print statement.
print
evaluates the given expression (in this case a string) and writes the resulting object to STDOUT (Console).
Very simple, now a little more complex.
#! python
if __name__ == '__main__':
print '%s %s!' % ('Hello', 'World')
This will also print “Hello World!”, but now we are using string formatting. String formatting is extremely useful. Let me show why.
#! python
if __name__ == '__main__':
hello = 'Hello'
world = 'World'
print '%s %s!' % (hello, world)
In this example the string “Hello” is assigned to the variable hello
and “World” assigned to world
. String formatting basically means to replace the objects inside the parentheses with the placeholders “%s” in the string. The placeholder (for example “%s”) is called conversion type. A conversion type defines to which data type the passed object will be converted.
myvar = 1
'Foo %s' % (myvar)
myvar
assigned to an integer will be converted to a string.
myvar = 1
'Foo %d' % (myvar)
myvar
assigned to an integer will be converted to an integer.
myvar = 'string'
'Foo %d' % (myvar)
myvar
assigned to a string will be converted to an integer? No! This will cause a TypeError
, because Python expects a number.
myvar = 1.1
'Foo %d' % (myvar)
myvar
assigned to a float will be converted to an integer? Yes! But this will not print “Foo 1.1”, but “Foo 1” because “%d” is an integer conversion type.
String formatting will not only be used if it comes to printing text. Each time you need to build a string from other objects, or concatenate two string objects, string formatting is useful and good style.
mynumber = 1
myword = 'Hi!'
mystring = str(mynumber) + ' ' + myword
print mystring
Or
mynumber = 1
myword = 'Hi!'
mystring = '%s %s' % (mynumber, myword)
print mystring
Both examples do exactly the same, but the second one is much more readable. And that’s what Python is all about, readability.
mynumber = 1
myword = 'Hi!'
mystring = '%d %s' % (mynumber, myword)
print mystring
Using “%d” instead of “%s” is even better because mynumber
is an integer and everything else than integer is unexpected, which we will tell the formatted string by using “%d” instead of “%s”.
Slightly more complex Hello World coming up.
#! python
def hello():
return 'Hello'
def world():
return 'World'
if __name__ == '__main__':
print '%s %s!' % (hello(), world())
This time we used functions to build the “Hello World!” string. The function hello()
returns a ‘Hello’ string object and the function world
returns a ‘World’ string object. Again we are using string formatting, to format the returned values by both functions into one string. Now, the last “Hello World!”.
#! python
def words_to_string(first_word, second_word):
return '%s %s' % (first_word, second_word)
if __name__ == '__main__':
print words_to_string('Hello', 'World!')
Functions are introduced by the def
keyword. Inside the parentheses you can define the function arguments, or leave them empty, if no arguments should be passed to the function. Isn’t it called “Method”? No, outside classes functions are called functions. Inside classes functions are called methods. The words_to_string
function needs two arguments, which will be used to build a new string. The new string will be returned by the function.
Indentation
Python does not use curly braces “{}” to define a block of code. Blocks are defined by indentation. Each time you begin a new block of code after a compound statement like if, for, while, def, class, …, you need to indent the block by one level.
def words_to_string(first_word, second_word):
return '%s %s' % (first_word, second_word)
or
if __name__ == '__main__':
print 'Hi!'
Common style defined by Python Enhancement Proposal 8 (PEP 8) is to use 4 spaces for each indentation level. Don’t mix tabs and spaces. Unexpected indents will raise an IndentationError.
if __name__ == '__main__':
print 'Hi!'
print 'Ho!'
IndentationError: unexpected indent
if statement
if
is an control flow statement, meaning you can influence the flow/order of your program. The if statement is introduced by the if
keyword and an expression, which evaluates to true or false. If the expression result is true, the if block will be executed, if the result is false, the block will not be executed. To compare objects, the comparison operators can be used.
if 1 + 1 == 2:
print '1 + 1 = 2'
or
mybool = True
if mybool:
print 'mybool is True'
or
mybool = False
if not mybool:
print 'mybool is False'
True and False
There are more objects which evaluate to true or false. Here are some examples.
Data Types True
mystring = 'foo'
: A not empty string is truemybool = True
: A bool with valueTrue
is of course truemynumber = 1
: A positive or negative number, which is not 0, is truemydict = {'key': 'value'}
: A not empty dict is truemylist = [1,2,3]
: A not empty list is true
Data Types False
mystring = ''
: An empty string is falsemybool = False
: A bool with valueFalse
is of course falsemynumber = 0
: 0 is falsemydict = {}
: An empty dict is falsemylist = []
: An empty list is false
Comparison Operators
Relational Comparison Operators
-
: (a > b) a greater than b
- < : (a < b) a less than b
-
= : (a <= b) a greater than or equal to b
- <= : (a <= b) a less than or equal to b
- == : (a == b) a equal to b
- != : (a != b) a not equal to b
Identity Comparison Operators
- is : (a is b) a and b are the same object
- is not : (a is not b) a and b are not the same object
Boolean Operations
- and : (a > b) and (a < 1)
- or : (a > b) or (a == b)
- not : not a
The strange if statement
As you may noticed the functions are defined outside the if statement. Qoute from a good Stackoverflow answer What does if name == ‘main’ do
When the Python interpreter reads a source file, it executes all of the code found in it. Before executing the code, it will define a few special variables. For example, if the python interpreter is running that module (the source file) as the main program, it sets the special name variable to have a value “main”. If this file is being imported from another module, name will be set to a different value.
[…]
One of the reasons for doing this is that sometimes you write a module (a .py file) where it can be executed directly. Alternatively, it can also be imported and used in another module. By doing the main check, you can have that code only execute when you want to run the module as a program and not have it execute when someone just wants to import your module and call your functions themselves.
The if statement is some kind of protection, which keeps Python from executing code, which should only be executed if the .py File is executed directly.
Import Python Modules
Python libraries are organized in modules. A module is a Python .py file. The name of the module is defined by the name of the .py file. A module “mymodule” would be a .py file called “mymodule.py”. Module names can also be represented by a folder. In this case a folder name is the module name and inside this folder is a .py file called “init.py”, which represent the .py file from which content can be imported. To load content from a module the import statement is used. The contents which can be imported from a module are variables, functions and classes. There are modules already shipped with your Python installation. These modules can be found in the Python Standard Library. User generated modules are shipped via Python Packages. Lots of useful packages can be found on the Python Package Index.
There are two ways to import contents from a module. You can import the namespace of a module, meaning you can access all exported contents of a module under the name of the namespace. The second way is, to import contents from a module directly into the namespace of your Python script.
#! python
import time
if __name__ == '__main__':
print time.time()
In this case the time module will be imported. All exported contents of time are accessible under the namespace “time”. Here we access the time
function from time and print the current time.
#! python
from time import time
if __name__ == '__main__':
print time()
Here we use the import syntax to directly import a function from the time module into the namespace of the Python script. You can import everything from a module into the script namespace by importing “”, from time import *
, but this is bad style. Don’t do it. If you need to import everything from a module, import the module name like import time
and access the contents of the module via the namespace time. Importing “” can easily cause name conflicts, which are confusing to debug sometimes.
What you learned by now
- Print an object
- Format strings
- Assign variables
- Define functions
- How to indent
- if statement
- Comparison Operators
- Boolean Operations
- if name == ‘main’
- Import and use modules
Exercise
Instead of just listing all language features of Python we will stop introducing new syntax and start using the learned knowledge for a first program. We will implement a script, which monitors a website.
Requirements
For monitoring a website, we need a HTTP client library. Python has two HTTP clients in its standard library, but they are complicated to use and badly designed. Instead we will use Requests. Requests wraps around the HTTP clients in the Python standard library by providing a really user friendly API. The script should also check for the request time. So we need a module, which provides an interface to the current time. We use the time module for that.
Install requests
To install Requests, we use the pip command. Activate your VirtualENV and enter the following command.
pip install requests
A clean install looks like this:
Downloading/unpacking requests
Downloading requests-1.1.0.tar.gz (337kB): 337kB downloaded
Running setup.py egg_info for package requests
Installing collected packages: requests
Running setup.py install for requests
Successfully installed requests
Cleaning up...
Introduction
HTTP GET with Requests
This is how you execute an HTTP GET request with Requests. Requests will return a Response object.
#! python
import requests
if __name__ == '__main__':
response = requests.get('http://aboutsimon.com/')
Time a GET request
The Python time module provides a time
function, which will return the time in seconds since the epoch (UNIX timestamp) as a floating point number. To time something we need a start time and an end time. Between start and end, we will execute the GET request. Subtract start from end and you will get the elapsed time for the GET request.
#! python
import requests
from time import time
if __name__ == '__main__':
start_time = time()
response = requests.get('http://aboutsimon.com/')
end_time = time()
elapsed_time = end_time - start_time
print 'GET request took: %f seconds' % (elapsed_time)
The “%f” in the string stands for float
, because elapsed_time
is of type float
and we like to see the precision of float
.
Access attributes from response
The Response
object from the GET requests provides a couple of attributes. With response.status_code
we can access the HTTP Status Code of the HTTP Server Response as integer. If everything is fine, the Status Code should be 200 for “HTTP OK”. response.content
will return the page content we requested as str
object, which is a ASCII string. The content itself isn’t that interesting for now, but the size of the content is. To get the size of a string we use the built-in function len. Built-in functions must not be imported, they are just there, like keywords (if, def, import etc).
#! python
import requests
from time import time
if __name__ == '__main__':
start_time = time()
response = requests.get('http://aboutsimon.com/')
end_time = time()
elapsed_time = end_time - start_time
print 'GET request took: %f seconds' % (elapsed_time)
print 'HTTP Status Code: %d' % (response.status_code)
print 'Page size: %d byte' % (len(response.content))
Your turn
Your exercise is, implement a Python script, which checks a Website.
- Define a function
get_website
, with a URL as argument, which executes the GET request and returns the reponse - Check if the reponse Status Code is 200, if yes print “HTTP Status Code: OK”, if not print an error message
- Check if the request took less than 0.5 seconds, if yes print the request time, if not print an error message
- Check if the response content size is greater than 0 bytes, if yes print the size, if not print an error message
- Read PEP 8 and check if your script is compliant to PEP 8.
In Part 2 of Python Lessons, I will post a solution, to this exercise.