In this chapter we are revisiting the things you learned during the tutorial, and give some example of applications for each of the new concepts that were introduced.
Learning outcomes: fundamentals of the python syntax. New semantics: data type, literal, sequences, mapping, keyword and positional arguments...
Prerequisites: you have read the python tutorial, sections 3 to 5.
An informal way to describe a programming language is to say that it "does things with stuff". These "stuff" are often formally called Data Types in computer science. In python, these data are called "objects": these can be described much more formally, but for now we will just mention that everything is an object in python.
Therefore, data types are sometimes called object types in some python textbooks. It doesn't make a difference and you can choose both terminologies. In sections 3 and 4 of the tutorial you used exclusively built-in types. Built-in data types are directly available in the interpreter, as opposed to other data types which maybe obtained either by importing them (eg from collections import OrderedDict
) or by creating them yourselves.
type(1)
a = 'Hello'
type(a)
Exercise: add a print
call in the statement above to see the difference with ipython's simplified print. What is the type of type
, by the way?
There are three distinct numeric types: integers (int
), floating point numbers (float
), and complex numbers (complex
). We will talk about these in more details in the numerics chapter.
There is a built-in boolean data type (bool
) useful to test for truth value. Examples:
type(True), type(False)
type(a == 'Hello')
3 < 5
Note that there are other rules about testing for truth in python. This is quite convenient if you want to avoid doing operation on invalid or empty containers:
if '':
print('This should not happen')
Refer to the docs for an exhaustive list of boolean operations and comparison operators.
In python (and many other languages) text sequences are named strings (str
), which can be of any length:
type('Français')
Unlike some languages, there is no special type for characters:
for char in 'string':
print(char, type(char))
Since strings behave like lists in many ways, they are often classified together with the sequence types, as seen below.
Sequence types support a common set of operations and are therefore very similar:
l = [0, 1, 2]
t = (0, 1, 2)
r = range(3)
1 in l, 1 in t, 1 in r
len(l), len(t), len(r)
l + l
t + t
But this won't make much sense for the range type though. Ranges are a little different:
r = range(10)
r
list(r)
They are usually used for loops or to generate other sequences. Ranges have a strong advantage over lists and tuples: their elements are given upon request, and ranges have therefore a very low memory consumption. See the following:
range(2**100)
list(range(2**100))
An OverflowError
tells me that I'm trying to create an array too big to fit into memory.
As mentioned earlier, strings also have much in common with lists:
'gg' in 'eggs'
"Tuple" is probably a new concept for you. It is a type quite specific to python. It is almost like a list, but it is immutable:
l[1] = 'ha!'
l
t[1] = 'ha?'
It is exactly this property which makes tuples useful, but this is not really obvious at the first sight. We'll leave it here for now.
Sets are an unordered collection of distinct objects:
s = {'why', 1, 9}
s.union({9, 'not'})
Sets are useful for realising operations such as intersection, union, difference, and symmetric difference.
A mapping object maps values (keys) to arbitrary objects (values). It is a collection of (key, value) pairs:
d = {'a':1, 2:'b'}
d
2 in d
1 in d
d['a']
Dictionaries are (together with lists) the container type you will use the most often.
Note: there are other mapping types in python, but they are all related to the original dict
. Examples include collections.OrderedDict
, which is a dictionary preserving the order in which the keys are entered.
Exercise: can you think of examples of application of a dict
? Describe a couple of them!
Literals are the fixed values of a programming language ("notations"). Some of them are pretty universal, like numbers or strings (9
, 3.14
, "Hi!"
, all literals) some are more language specific and belong to the language's syntax. Curly brackets {}
for example are the literal representation of a set
. This syntax has been added for convenience only:
s1 = set([1, 2, 3])
s2 = {1, 2, 3}
s1 == s2
d1 = dict(bird='parrot', plant='crocus')
d2 = {'bird':'parrot', 'plant':'crocus'}
d1 == d2
Using one or the other way to construct your containers is a matter of taste, but in practice you will see the literal version more often.
In the tutorial you've learned about for
and while
loops (the latter being much less frequent). I'll just summarize the most important information here:
This is the major difference with loops you might have known from other languages (and this is one of the best things in python):
Unpythonic:
seq = ['This', 'is', 'very', 'unpythonic']
for i in range(len(seq)):
print(seq[i])
Pythonic:
seq[-1] = 'pythonic'
for s in seq:
print(s)
for i in range(xx)
is almost never what you want to do in python. If you have several sequences you want to iterate over, then do:
lis = [1, 2, 3, 5]
for s, l in zip(seq, lis):
print(l, s)
Blocks are defined via their indentation, and not via brackets or begin .. end
statements. Hate it or love it, this is how it is ;-). I learned to like this style a lot. Although the indentation could be anything (two spaces, tabs...), the recommended way is to use four spaces.
These are the positional arguments and keyword arguments.
keyword arguments are preceded by an identifier (e.g. name=
) and are attributed a default value. They are therefore optional and the order in which they are given to the function does not matter:
def f(arg1, arg2, kwarg1=None, kwarg2='None'):
print(arg1, arg2, kwarg1, kwarg2)
f(1, 2, kwarg2='Yes', kwarg1=3.14)
f(1, 2, 'Yes', 'No')
I am not a big fan of this feature because it reduces the clarity of the code and recommend to always use the kwarg=
syntax. I am not alone in this case, and therefore python implemented a syntax to make calls like above illegal:
# The * before the keyword arguments make them keyword arguments ONLY
def f(arg1, arg2, *, kwarg1=None, kwarg2='None'):
print(arg1, arg2, kwarg1, kwarg2)
f(1, 2, 'Yes', 'No')
positional arguments are named like this because their position matters, and unlike keyword arguments they don't have a default value and are mandatory. Forgetting to set them results in an error:
f(1)
Back to the table of contents, or jump to the next chapter.