None .. An html document created by ipypublish
outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2 with segments: - nbsphinx-ipypublish-content: ipypublish sphinx content
5. Variables and control structures¶
Basile Marchand (Materials Center - Mines ParisTech / CNRS / PSL University)
5.1. Define and manipulate variables¶
5.1.1. Concretely, what is a variable?¶
Generally in computer science, a variable is a symbol associated with a value. The value in question can be of any type. Depending on the programming language considered, a variable can be typed (i.e. when it is declared an immutable type is associated with it) or not (i.e. the value associated with the variable can change type during program execution). Python is an untyped programming language. In other words, if you declare a variable A containing a character string, you can later in the program associate it with a number for example.
The Python language, compared to low level lanagages such as C, greatly
simplifies the manipulation of variables. Classically, to create a
variable, a distinction is made between the declaration operation and
the assignment operation. Typically in C ++ the first step consists in
declaring a variable A with its type. And secondly, using the =
operator, we assign this variable a value of the corresponding type. For
example to define an integer in C ++:
int an integer;
an integer = 1;
In Python the declaration step is included in the assignment. Indeed since the variables are not typed in Python they cannot be declared in advance. Strictly if it is possible, but is strictly useless given the internal mechanisms of the language.
The question that can then be asked is where is the value associated with the variable located in the computer? In a file? And no, it is located in the RAM. How does it work : When in a Python code we create a variable A associated with a value of a certain type (floating number for example) the language machinery will automatically ask the computer to give it a box in the memory (the size of the box depends on the type of value we want to store there). The Python language then recovers a pointer to the allocated memory box (a memory address) and it associates with this memory address the variable that we are going to handle. The Python language is said to be high level among other things because of this process of creating variables in memory which is automated and transparent for the user. Unlike the low-level language, such as C or FORTRAN for example where the programmer must explicitly request the allocation of a memory slot before storing a value there.
Tip: to know the address in memory of a variable in Python just do:
[1]:
ma_variable = 12.4 # on définit une variable nommée ma_variable et l'on y associe la valeur 12.4
hex(id(ma_variable)) # on demande l'adresse mémoire en hexadecimal
[1]:
'0x7f42ba7ac2b0'
5.1.2. How do you define a variable? Can we define everything as a variable?¶
In Python, as in a number of other languages, the assignment of a value to a variable (which in passing in Python creates the variable if it does not exist) is done using the symbol = The syntax valid for all types is as follows:
name_of_the_variable = associated_value
For example :
[2]:
var1 = 1.3
Note concerning the naming of variables: the PEP8
The naming of variables is an important element, whatever the programming language. Indeed a bad choice in the name of the variables does not affect the operation of the code but it generates:
Programming errors.
Code that is difficult to read is understandable.
A code that is difficult to maintain and develop.
The first most important point is therefore that you always have to name the variables in such a way that we know exactly with its name what it refers to.
There are “official” recommendations for Python on variable naming, this is PEP8.
Among the various recommendations contained in PEP8, the one concerning the naming of variables states that: * Variable names start with a lowercase letter * If the name consists of several words, they are separated by **_**
my_variable
Tip: to know the type of a variable just use
[3]:
type(ma_variable)
[3]:
float
5.2. The basic types (so not the only ones possible)!¶
We will now go over the different base types available in Python. Basic because, as we will see later in the course, Python allows you to define additional new types. We will also see that the use of complementary modules makes it possible to handle other types such as matrices for example.
5.2.1. Numbers: integers, floats and complexes¶
Like any computer language, Python allows the manipulation of numbers of all types, integers, floats and complexes.
Integers are objects of type int (for integer).
[4]:
un_entier = 127
## ou bien
un_entier = int(127)
un_entier, un_autre = 128,25
All the usual operations addition, subtraction, multiplication, division and raising to the power are already defined and can be used on integers.
[5]:
a = 1
b = 3
print(a+b) ## Addition
print(a-b) ## Soustraction
print(a*b) ## Multiplication
print(a/b) ## Division
print(a//b) ## Division entière
print(a%b) ## Reste de la division entière
print(a**b) ## a à la puissance b
4
-2
3
0.3333333333333333
0
1
1
Warning: In Python 2.X the division / of two integers actually returns the whole division while in Python 3.X it is indeed a floating division.
[6]:
%%python2
a = 1
b = 3
print("a/b = {}".format( a/b ))
a/b = 0
The reals are objects of type float for float
[7]:
un_flottant = 1.34
type(un_flottant)
[7]:
float
Floats are defined in Python using the same logic as integers, beware the comma is represented by a point.
[8]:
a = 1.2387
## ou bien
a = float(1.2387)
We can also define \(0.000123\) by \(1.23 e^{-4}\) as follows
[9]:
1.23e-4
[9]:
0.000123
As for integers all the usual operations are defined and usable in Python
[10]:
a = 1.24
b = 2.45
print(a+b) ## Addition
print(a-b) ## Soustraction
print(a*b) ## Multiplication
print(a/b) ## Division
print(a**b) ## a puissance b
3.6900000000000004
-1.2100000000000002
3.0380000000000003
0.5061224489795918
1.6938819049274374
When mixing types within expressions Python automatically takes care of converting the operands into the appropriate type.
For example the sum of an integer and a float returns a float
[11]:
a = 2
print(type(a))
b = 2.
print(type(b))
c = a + b
print(c)
print(type(c))
a = 0.1
b = 0.2
c=a+b
print(a)
print(b)
print(c)
<class 'int'>
<class 'float'>
4.0
<class 'float'>
0.1
0.2
0.30000000000000004
The complexes are defined by a doublet of two numbers the real part and the imaginary part. In Python the definition of this doublet can be done in two different ways
[12]:
## Utilisation du constructeur "complex"
un_complex = complex(1,1) # correspond à 1+1i
## Utilisation de la constante "j"
un_complex = 1+1j
Warning: there is no operator __*__ between the 1 and the j if you try to put this operator in the definition of a complex it will cause an error
>>> x=1
>>> y=2
>>> c = x+y*j
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-26-b894b6a64e03> in <module>()
1 x=1
2 y=2
----> 3 c = x+y*j
NameError: name 'j' is not defined
Tip: if you want to handle complexes involving variables without having to rewrite the complex command each time, the easiest way is to proceed as follows
[13]:
i = 1j
x = 1
y = 2
c = x+i*y
print(c)
(1+2j)
Obviously basic operations on complex numbers already exist in Python.
[14]:
c1 = 1+1j
c2 = 2+3.45j
print(c1+c2)
print(c1-c2)
print(c1*c2)
print(c1/c2)
(3+4.45j)
(-1-2.45j)
(-1.4500000000000002+5.45j)
(0.3427134098412199-0.09118063197610438j)
But there are also other specific operations available
[15]:
print(c1.real) ## Partie réelle
print(c1.imag) ## Partie imaginaire
print(c1.conjugate()) ## Conjuguée de c1
print(abs(c1)) ## Module de c1
1.0
1.0
(1-1j)
1.4142135623730951
5.2.2. Booleans¶
The boolean type is used in Python for writing logical expressions, tests. The Boolean type can only take two values True or False.
[16]:
un_vrai = True
un_faux = False
In order to build logical expressions we have in Python the following logical operators:
Comparison operators (applicable to integers and floating point numbers):>,>=, <, <=, ==,!=
Connectors: and, or, not, == or is, in
Below are some examples of logical expressions:
[17]:
a = 2.3
b = 10
print( a <= b)
print( a >= b)
print( (a <= b) is True )
print( (a <= b) == False )
print( (a <= b) or (a > b) )
print( ( (a <= b) or (a > b) ) and ( a>b ) )
print( not (b>10.))
True
False
True
False
True
False
True
5.2.3. The strings¶
The last native type in Python is the string type for strings. Strings in Python can be defined in three different ways.
[18]:
une_string = "Hell World"
### ou bien
une_string = 'Hello World'
### ou encore
une_string = """Hello World"""
These three methods of definitions all have an interest. The first allows you to define character strings containing apostrophes. The second allows you to define character strings containing quotes. Finally, the last allows to keep the formatting of the character string when it is displayed with the command print for example
[19]:
une_chaine_sans_formatage = "Bonjour tout le monde, comment allez vous ?"
print( une_chaine_sans_formatage )
une_chaine_avec_formatage = """Bonjour tout le monde,
comment allez vous ? """
print( une_chaine_avec_formatage )
Bonjour tout le monde, comment allez vous ?
Bonjour tout le monde,
comment allez vous ?
Note: the last method of writing a character string, based on triple quotes, also allows you to define comment blocks.
Handling character strings
We will now see how we can handle character strings. This may seem incidental but for the processing of experimental data a large part of the work is the processing of files and therefore of strings representing their contents. It is therefore essential to know how to process character strings quickly and efficiently. Here below are some elementary operations on character strings.
[20]:
chaine_a = "debut"
chaine_b = "fin"
Concatenation of character strings:
[21]:
res = chaine_a + chaine_b
print(res)
res = chaine_a + " " + chaine_b
print(res)
debutfin
debut fin
Formatting a character string:
[22]:
ma_chaine = "Une chaine de caractère avec un entier {} un flottant {} et un booléen {}".format(1,2.34,False)
print( ma_chaine )
Une chaine de caractère avec un entier 1 un flottant 2.34 et un booléen False
[23]:
ma_chaine = "Une chaine de caractère avec un entier {2} un flottant {1} et un booléen {0}".format(False,2.34,1)
print( ma_chaine )
Une chaine de caractère avec un entier 1 un flottant 2.34 et un booléen False
Since Python 3.6 it is possible to format a string more concisely using the following syntax:
f "a string {variable} and / or {python expression}"
[24]:
pi=3.14
print( f"pi={pi} et pi*pi={pi*pi}")
pi=3.14 et pi*pi=9.8596
Find if a substring is in a string:
[25]:
sous_chaine = "bu"
print( sous_chaine in chaine_a )
True
Separate a string into a set of strings at the level of a given character:
[26]:
res = chaine_a + "_" + chaine_b
print(res)
after_split = res.split("_")
print(after_split)
print(after_split[0])
print(after_split[1])
debut_fin
['debut', 'fin']
debut
fin
Join a list of string with a given delimiter:
[27]:
print(after_split)
"-".join(after_split)
['debut', 'fin']
[27]:
'debut-fin'
Find out the size of a list
[28]:
print(chaine_a)
len(chaine_a)
debut
[28]:
5
Extract a sub-part (slice)
[29]:
chaine_a[1:3]
[29]:
'eb'
[30]:
chaine_a[::2]
[30]:
'dbt'
*Slicing in general*
In general, the syntax for extracting a slice is of the form:
start:end:step
With default:
start = 0
end = len (obj)
step = 1
| **Attention**
| In the slice the value of ``end`` is **excluded**
5.3. Control structures¶
5.3.1. Principle¶
The last point addressed in this first part is what we call in computer science the structures of controls. We saw previously that one can easily write logical expressions relating to variables. What we haven’t seen yet is what the result of these logical expressions can be used for in the code and that’s where the control structures come in. Indeed, the interest of a computer program is generally to perform a certain number of tasks / actions. But depending on the input values of the program, the actions to be performed are potentially not the same, which is why we need to set up logical expressions associated with the control structures in order to steer the program and the processing flow.
Concretely, let’s imagine that I make a program which, according to grades, automatically tells me if a student validates my module or must go to catch-up. Once the score has been calculated, I have to test whether it is greater than or equal to 10 or if it is less than 10 because, depending on the case, consider the program should not display the same message. This is what the use of control structures consists of.
5.3.2. if … elif … else¶
In Python the only commands used to orient the course of a program are if, elif and else. What you will surely have guessed can be translated by if, if not if, if not.
if a _first_ condition:
action _associated_ with _the_ first _condition
elif a_ other _condition:
action_ associated _has_ the _second_ condition
else:
action _performed_ by _default
Of course, the syntax allows you to have as many elif as necessary, meaning from 0 to N. However, you can only have one else and you must necessarily start with an if. Condition objects / variables must be of type boolean or int. Indeed Python can assimilate an integer to a boolean by following the following rule if the integer is equal to 0 it is associated with False, if it is different from 0 it is associated with True.
- Important: syntax rule You may have noticed: *at the end of each
of the if, elif, else lines there is the character “* : *” * there is no keyword to specify the end of the control structure (no endif) *the command lines located within the control structure (under the if, elif, else commands) are indented.
This is a fundamental concept in Python, all instruction blocks begin with the character “* : *” and are delimited by the level of indentation of the code. For example :
if a_condition:
## Beginning of the instructions executed if the condition "some_condition" is true
a = 2
print (a)
b = 3
print (b)
## End of the instructions contained in the if
### Resumption of the executed code that we pass in the if or not
a = 234
b = a* * 3
print (b)
By following this indentation rule it is quite possible to nest several blocks of if, elif, else statements within each other. For example :
if condition _1:
if under_ condition _11:
a_ action
elif under _condition_ 12:
one _other_ action
else:
yet _one_ other _action
elif condition_ 2:
if under _condition_ 21:
pass
elif:
a _action
else:
a_ action
You see in passing the keyword pass. The latter in fact is useless,
since it does not perform any action. Its only interest is to allow to
respect the rules of syntax. In the previous case, it is used to define
a elif block associated with a if block which does not perform
any action.
Note on indentation:
For the indentations of your code you can use:
The tab key
An arbitrary number of spaces (usually 4) However, be careful not to mix tabulation and space in your code, otherwise you will get an error during code execution. Most text editors automatically replace tabs with 4 spaces. However, some editors under Windows in particular do not do this, which can cause errors. The error message returned by Python is quite explicit and is of the form
TabError: inconsistent use of tabs and spaces in indentation
[ ]: