In this notebook we'll get to know the syntax of the Python language, and some basic data types and structures. Later we'll use these types and structures everywhere.
In Python, comments begin with a # symbol, and last until the end of the line. A comment can be at the beginning of a line, or can follow a space or a tab. But if you put it inside a string, it will not be a comment anymore. A # inside of a string only means a single #.
# this is the first comment
SPAM = 1 # this is the second comment
# ... this is the third one.
STRING = "# This is not a comment, because it is between quotation marks."
Comments are for the programmer as a reminder, or they can help other programmers in understanding the code. After a while, even our own code will be a faint memory, thus, it pays off to comment our own code for ourselves extensively.
We can use the notebook as a simple calculator. We can write an expression, and it calculates its value. The syntax of the expression goes as usual: +, -, * and / operations work as in most other languages (such as Matlab, Fortran or C/C++). Brackets are for grouping operations, or for overriding the default order of operations.
2 + 2
50 - 5*6
(50 - 5*6) / 4
Integer numbers such as 2, 4 or 20 are of the type int, real numbers such as 5.0 or 1.6 are of the type float. In Python 3, division (/) always returns a floating point value. To implement integer division, we can use the // operator, to get the remainder, we can use the % operator.
8 / 5 # division returns a float even in the case of integers
17 // 3 # integer division
17 % 3 # the % operator returns the remainder
5 * 3 + 2 # check
We can use the ** operator for exponentiation. (Attention, in most languages it is the ^ operator!)
5 ** 2 # square of 5
2 ** 7 # 2 to the 7th power
Python prefers floating point numbers to integers in certain operations. Those operations that mix types will always convert integers to floats.
3 * 3.75 / 1.5
7.0 / 2
Sometimes we have to use integers, but we got floats. Then, conversion can be done using the functions int()
and float()
.
int(3.1415)
float(42)
Python can work with complex values. We can denote the imaginary part by j or J. Complex numbers can be written as a sum of the real and imaginary parts.
1j * 1J
3+1j*3
(3+1j)*3
(1+2j)/(1+1j)
Complex numbers are sometimes represented by a pair of floating point numbers. We can address the real and imaginary parts of a z
complex number by the z.real
and z.imag
commands. (For those reader who have already covered the topic of classes: real
and imag
are two attributes of the complex
class.)
(1.5+0.5j).real
(1.5+0.5j).imag
Conversion to int or float by the functions int()
and float()
do not work for complex numbers. But we can get the absolute value of a complex number by using the abs()
function.
float(3.0+4.0j) # ez nem működik
Here we've seen our first Python error message! It is rather telling.
abs(3.0+4.0j) # sqrt(a.real**2 + a.imag**2)
When programming, we usually store information in useful variables. Our code will not refer to concrete numeric values, but to variables. This enables us to run the same algorithm for different input values as well. Variable names can only contain the characters of English language, and some other special characters of which _
is the most common.
width # only contains letters
corridor_length # contains the _ character as well
Choose variable names such that they are meaningful.
As in most other programming languages, we can assign a value to our variables by using the =
symbol. After such an assignment, the interpreter is waiting for a new command, it seems to have done nothing:
width = 20
height = 5*9
But in the memory, the variables width
and height
have been created, we can use them later on. Let us calcaulte the product o the two variables!
width * height
If a variable is not yet defined (we have not assigned a value to it yet), then we get an error message if we want to use it. Note that the error message tells you about the problem quite verbosely!
n # we still have not defined the variable n
The value of the last printed expression is stored in the _
variable in Jupyter. Thus, if you use Python as a calculator, then you can chain your calculations in the following way:
tax = 12.5 / 100
price = 100.50
price * tax
price + _
round(_, 2) # rounding to two decimal values
Use this variable only as readable. Do not assign a value to it, because assigning a value to it creates a local variable with the same name, the prevents the access to the built-in variable which behaves in this magic way. (If we create a local variable with the name of a global variable, the interpreter will use te local copy instead of the global one)
In a Jupyter Notebook, we can refer to not jsut the latest output of a cell, but former ones as well. For example, the output of the second cell was:
Out[2]
For a program, to be able to deal with different inputs, or to make its pards dependable on former values, we have be able to evaluate certain conditions. Let us think of the solution of a quadratic equation! Depending on the sign of the discriminant, real or complex roots exist. Thus, a program that calculates the solutions has to 'decide' based on tis input values. The decision is based on the evaluation of a condition (e.g. is the discriminant positive?), which can be true or false. A variable that can store true or false values is called boolean. (This is a type - more advanced readers can think of a class - like int or float were before.)
To test whether two objects are equal, we use the ==
operator.
1 == 1 # is 1 equal to 1?
1 == 2 # is 1 equal to 2?
To test whether two objects are not equal, we use the !=
operator.
1!=2 # is 1 not 2?
In the case of numbers, we can decide which one is greater with the help of the <>
operators.
1>2
1<2
1j+3>2 # this relation cannot be used for complex numbers, as the error message nicely tells us
We can store a true or false value in a variable.
trueorfalse = 2*2==5
trueorfalse
We may chain relations as well.
b=2
1 < 2 == b
b=3
1 < 2 == b
We can create longer logical expressions with the and and the or operators. We can change the result of any logical expression or logical variable with the help of the not operator.
not 2*2==5
The and, or and not operators are evaluated after the relational expressions, that is, we do not use any grouping by brackets.
Out of the three logical operations, not is evaluated first, and or is evaluated last.
Thus, A and not B or C
is the same as (A and (not B)) or C
. We can use brackets of course to override default precedence.
b=3
((1==2) and (3==4)) or (b==3)
Apart from numbers, we can do operations on strings such as words in Python. Strings have to be placed between single ('...') or double ("...") quotes. Between the two notations, there are no remarkable differences. The \symbol can be used to escape quotes inside a string.
'spam eggs'
'doesn\'t'
"doesn't"
'"Yes," he said.'
"\"Yes,\" he said."
'"Isn\'t," she said.'
Output strings are displayed between quotes, special characters escaped by \ symbols. The print()
command creates a much more readable output, it leaves the quotes and displays special characters.
print('"Isn\'t," she said.')
s = 'First line.\nSecond line.' # \n means a newline
s # without print(), \n stays in the output
print(s) # with print, \n creates a newline
If you don't want characters after a \ symbol to be interpreted as special, then you may use a raw string by putting an r letter in front of the first quotation mark.
print('C:\some\name') # \n means a newline
print(r'C:\some\name') # r is in front of the first quote
Sometimes we would like to create strings exactly as we type them. A pair of a triple """
or '''
makes it possible. Then, newlines will automatically added to the strng, but this behaviour can be escaped by a \ at the end of the line.
print("""\
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
""")
We can concatenate string with the +
operation, and we can multiply them by the *
operation.
3 * 'un' + 'ium'
Two literal strings (that are not stored in a variable, or that are not created on the fly by a function) are concatenated by the interpreter by default.
'Py' 'thon'
For variables, it gives an error.
prefix = 'Py'
prefix 'thon' # it cannot concatenate a varable and a literal string
If you want to concatenate a literal string with a variable or two variable, then use the +
operator.
prefix = 'Py'
prefix + 'thon'
Concatenating literals is very useful for handling muliline strings.
text = ('We can put multiple strings into the brackets '
'to be able to concatenate them.')
text
Python assigns an index to each character in the string. The index 0
corresponds to the first character, the index 1
to the next etc. (This convention is similar to that of C.)
word = 'Python'
word[0] # character at position 0
word[5] # character at position 5
Indices may be negative as well. Then, we cound from the right:
word[-1] # last character
word[-2] # last but one character
word[-6]
Moreover, slicing is also supported on top of indexing. While indexing returns one character, slicing returns a substring:
word[0:2] # characters from position 0 (included) to position 2 (not included)
word[2:5] # characters from position 2 (included) to position 5 (not included)
First index is always included in the result, last index is not. This makes it possible for s[:i] + s[i:]
to be equal to s
.
word[:2] + word[2:]
word[:4] + word[4:]
Indices of slices have useful default values. The default value of a left out first index is 0, the default value of a left out second index is the length of the string.
word[:2] # # characters from the start position to position 2 (not included)
word[4:] # # characters from position 4 (included) to the end position
word[-2:] # characters from the last but one until the end
Let us note, that -0 equals to 0, thus it won't start counting from the right!
word[-0] # mivel -0 és 0 egyenlőek
In the case of nonnegative indices, the length of the slice is the difference of the indices, if both are inside the string boundaries. For example, the length of word[1:3]
is equal to 2.
If we use too big indices, the result is an error message:
word[42] # the string word has only 7 characters
Python's strings are immutable, we cannot rewrite any of their parts. Thus, if we assign a value to a position of a certain index, we get an error:
word[0] = 'J'
If we need another string, we may create a new one.
'J' + word[1:]
word[:2] + 'py'
The built-in len()
function returns the length of the string.
s = 'legeslegelkáposztásíthatatlanságoskodásaitokért'
len(s)
Python knows several complex data types that group different values. A very useful and multi-faceted complex datatype is the list
, where we can add inputs as comma separated values in a square bracket. The values of a list don't have to be of the same datatype, but in most cases, they will be.
a = ['spam', 'eggs', 100, 1234]
a
['spam', 'eggs', 100, 1234]
Just as strings, lists can be indexed and sliced.
a[0]
a[3]
a[-2]
a[1:-1] # slicing returns a new list
Lists support concatenation:
a[:2] + ['ham', 2*2]
3*a[:3] + ['Boe!']
As opposed to strings, lists are mutable. We can modify any of their elements.
a[2] = a[2] + 23
a
We can give values to slices, this can even change the number of elements in a list.
a[0:2] = [1, 12] # rewriting some elements
a
a[0:2] = [] # deleting some elements
a
a[1:1] = ['bletch', 'xyzzy'] # inserting some elements
a
a[:0] = a # inserts a copy of itself into the first position
a
The built-in len()
function may also be used for lists.
len(a)
Lists are embeddable, a list may contain other lists.
a = ['a', 'b', 'c']
n = [1, 2, 3]
x = [a, n]
x
x[0]
x[0][1]
x[0][1]
Sometimes we would like to know the position of a given element inside a list, this can be done with the .index()
function (method).
cars=['skoda','vw','merci','mazda']
cars.index('merci')
As we've seen, strings are also indexable. We can also ask the position of a character inside a string.
letters='abcdef'
letters.index('e')
Another common problem is to decide whether an element is in a list. We can use the in operator for such questions.
Tage_der_Woche=['Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag','Sonntag']
'hetfo' in Tage_der_Woche
'Montag' in Tage_der_Woche
Sometimes we would like to store data not in a certain order, rather according to certain labels. For example, in foreign language dictionary, where we pair English expressions with expressions from the other language. For these structures, the ordering is not very meaningful, such as for properties of some objects. Let us have a car, that is
These properties define the car clearly, independent of their order. Such a data structure is a dictionary (in shorthand dict) in Python. Creating dictionaries with the help of keys and corresponding values goes as follows:
tel = {'John': 4098, 'Simon': 4139}
tel
Here, we can refer to an element by its key.
tel['John']
We can add a new element to the dict also with a similar syntax.
tel['George'] = 4127
tel
We cannot only give numbers as values:
tel['Jane']='I DON\'T KNOW HER NUMBER'
tel
We delete an element like
del tel['Simon']
tel
We can access all the keys by using the .keys()
function (method).
tel.keys()
Sometimes it is worth to convert the above keys to a list with the list()
command.
list(tel.keys())
Is George in the dictionary?
'Géza' in tel
Note that even if Jane
is in the dictonary, we still may not know her number.
'Jane' in tel
tel['Jane']
Thus, in
checks if a string is among the keys of a dict.
We can defince dictionaries with the dict()
function using another syntax as well. It will prove useful when dealing with keyword arguments in functions, or the plotly
module.
tel2=dict(Lydia=1234,Mary=4321,Kitty=5567)
tel2
As we have already seen, we can convert an object to an integer with the int()
function, or to a float with the float()
function, and we have seen an example of converting something to a list. We can convert objects to boolean variables as well with the bool()
function. In the following section, we will have a look at some examples of the behaviour of objects on boolean conversion.
A number or a string gives True.
bool(1.0)
bool('szoveg')
A nonempty list or an existing object gives True as well.
bool([1,'Bela'])
An empty string, an empty list and the number 0 gives False.
bool(0)
bool(0.0)
bool('')
bool([])
A seemingly wrong example.
'a' == ('a' or 'b')
'b' == ('a' or 'b')
'a' == ('a' and 'b')
'b' == ('a' and 'b')
Why is the second example False, if the first is True? Why is the third example False, if apparently, the similar fourth gives True?
At this point, it may seem that and and or are not working properly. If we delve into the steps the Python interpreter makes, it will turn out that it functions as it should. But it is not what we first expected! The first two examples do not check whether the character in front of == is inside the brackets. What happens exactly?
When Python meets an or inside the brackets, it goes though all of the objects connected by the or, and gives back the value of the first element that can be evaluated as True. Thus, it won't give True or False, but tha value of the variable! Whereas and returns the value of the last variable if all objects were evaluated as True. This behaviour of boolean operators is called short circuit, and it is similat in many other programming languages as well.
Thusm if we would like to test whether an expression is equal to any of a set of other expressions, we have to formulate it as follows.
(('a' == 'a') or ('a' == 'b'))
(('b' == 'a') or ('b' == 'b'))