Introduction to Python Programming. Section 5. Variables and Types

5 Variables and Types

5.1 Objectives

In this section you will learn:

  • That Python is a dynamically (weakly) typed language.
  • About various types of variables (data types) in Python.
  • How to create variables and initialize them with values.
  • About dynamic type interpretation.
  • How to determine the type of a variable at runtime.
  • How to force (cast) a variable to have certain type.
  • About local and global variables.
  • That using global variables can lead to problems.
  • About shadowing of variables.

5.2 Why learn about variables?

Variables are containers. The reason for using them is to store useful information such as values, text strings, etc. This encompasses many different scenarios, some of which you already encountered earlier in this textbook. For example, in Section 2 we used several times the fact that the value of π is stored in Numpy’s variable named pi:

  import numpy as np
  print(np.pi)

3.141592653589793

In Section 3 we typed cmap=’jet’, cmap=’ocean’ or cmap=’viridis’ to store the name of a color map in a variable named cmap.

In Section 4 you learned how to parse text strings with the for loop:

  txt = ’Hello!’
  for c in txt:
      print(c, end= ’)

H e l l o !

Here, the variable c is used to store the next character from the text string txt in each cycle of the for loop.

5.3 Statically vs. dynamically typed languages

In many languages including C/C++ and Java, the type of each variable must be declared in advance. We say that these languages are statically (strongly) typed. In contrast to that, Python is dynamically (weakly) typed. This means that the type of each variable is determined at runtime depending on the value that is assigned to it. In this section we will discuss various aspects of working with variables in Python ranging from trivial to advanced.

5.4 Types of variables (data types) in Python

In Python, variables can have the following basic types:

  • text string (str) ... Sequence of characters enclosed in quotes.
    Example: txt = ~Hello!~
  • Boolean (bool) ... Either True or False.
    Example: flag = True
  • integer (int) ... Integers are unlimited in size and have no maximum value.
    Example: n = 255
  • real number (float) ... Real (floating point) numbers.
    Example: val = 7.49
  • complex number (complex) ... Complex numbers with a real and imaginary part.
    Example: z = 2 + 3j

Python also has container data types for more advanced applications:

  • list (list),
  • tuple (tuple),
  • dictionary (dict),
  • set (set).

In this section we will focus on the basic data types, as well as on various general aspects of variables. Text strings were discussed in great detail in Section 4. Boolean values, variables and expressions will be discussed in Section 6. The container data types will be discussed in Section 7.

5.5 Using a non-initialized variable

Every variable must be initialized before use, otherwise the interpreter will complain:

  print(5*w)

on line 1:  
NameError: name ’w’ is not defined

5.6 Various ways to create variables and initialize them with values

In Python, every variable is an object, and therefore the process of its initialization is different and more flexible than in statically typed languages. Let’s look at integers for example. The most common way, of course, is to type something like:

  n = 255
  print(n)

255

It is possible to initialize multiple variables with the same value at once:

  m = n = p = 0
  print(m, n, p)

0 0 0

And it is also possible to pass the desired value to the constructor of the class int by typing:

  n = int(255)
  print(n)

255

The value can be omitted, in which case the default value 0 will be used. In other words, the following line defines an integer variable m and initializes it with zero:

  m = int()
  print(m)

0

As you already know, it is possible to use an existing variable to initialize the value of a new variable:

  a = 1
  b = 2.5
  c = 0.5
  d = (a + b) / c
  print(d =, d)

d = 7.0

Of course, apples cannot be mixed with oranges. When we try to add a number to a text string, then the interpreter rightfully complains:

  a = My car is a Ferrari.
  b = 3.5
  c = a + b

  on line 3:
  TypeError: Can’t convert ’float’ object to str implicitly

More to follow in the next subsection.

5.7 Casting variables to text strings

What we showed in the previous subsection can be taken one step further: It is possible to pass a value or variable of any basic type (int, float, bool, ...) or container type (list, tuple, ...) to the constructor of the text string class, converting it into a text string. This is called casting. The following example casts a real number to a text string:

  x = 2.17
  xstr = str(x)
  xstr

  ’2.17’

Booleans can be cast to text strings in the same way:

  flag = False
  flagstr = str(flag)
  flagstr

  ’False’

And it works for container data types as well. The last example here casts a list to a text string:

  L = [2, 3, 5, 7, 11]
  Lstr = str(L)
  Lstr

  ’[2, 3, 5, 7, 11]’

5.8 Casting can be tricky sometimes

In the previous subsection we have shown that variables of all types can be cast to a text string. This also works the other way round, and other casts are possible, but only if such a cast makes sense. Sometimes the result can be surprising. For example, a Boolean variable can be initialized with a text string (nonempty string = True, empty string = False). So if the text string is ’False’, the resulting Boolean will be True:

  txt = ’False’
  flag = bool(txt)
  flag

  True

And,

  txt = ’’
  flag = bool(txt)
  flag

  False

For compatibility with C/C++ and other languages, Booleans can also be initialized with numbers (nonzero = True, zero = False):

  num = 2.5
  flag = bool(num)
  flag

  True

and

  num = 0
  flag = bool(num)
  flag

  False

One last example: A text string containing a list can be cast to a list, but the result might not be what one would expect. The result will not be the original list – instead, it will be a list of individual characters that form the text string:

  txt = ’[1, 2, 3]’
  L = list(txt)
  L

  [’[’, ’1’, ’,’, ’ ’, ’2’, ’,’, ’ ’, ’3’, ’]’]

5.9 Inadmissible casting

If a text string contains a number, it can be cast to integer or float:

  txt = ’10’
  val = int(txt)
  val

  10

However, if one tried to cast to a number a text string which does not represent a number, then the interpreter would rightfully complain:

  txt = ’Monday’
  val = int(txt)
  val

  on line 2:
  ValueError: invalid literal for int() with base 10: ’Monday’

5.10 Dynamic type interpretation and its abuse

In Python, types of variables do not have to be declared in advance. Instead, the type of a variable is determined by the last value that was assigned to it. This also means that the type of a variable can change at runtime. Let us look at the following code:

  a = 5
  print(a)
  a = 3.14
  print(a)
  a = Hello!
  print(a)
  a = True
  print(a)

5  
3.14  
Hello!  
True

Initially, the type of the variable a was an integer (int), then it was changed to a real number (float), then it became a text string (str), and finally it became a Boolean variable (bool). However, the above code is abusing Python’s flexibility, and doing so is a great way to shoot yourself in the leg. There is a good reason for much tighter type control in C/C++ and other languages – it makes the code less prone to mistakes.

Avoid abuse of dynamic type interpretation. A variable, once created for a purpose, should serve that purpose. If you need another variable for something else, just create another variable.

Also:

Have names of variables reflect their contents. For example, phone_number is a good name for a variable storing a phone number. Using the name x17 for such a variable is not against any rules, but it makes your code unreadable.

In general, do not be too inventive with names of variables (any other aspects of your code). You should not leave anything for the reader to figure out – reading your code should not be an intellectual exercise.

5.11 Determining the type of a variable at runtime

The simplest two ways to determine the type of a variable at runtime is either to use the function isinstance or the function type. Let’s begin with the former.

The function isinstance(var, T) returns True if the variable var has type T and False otherwise:

  var = ’Hello!’
  test = isinstance(var, int)
  print(test)

False

And,

  var = 42
  test = isinstance(var, int)
  print(test)

True

Here is a slightly more complex example which includes a function definition and an if-elif-else statement:

  def printtype(a):
      if isinstance(a, str):
          print(’a is a text string.’)
      elif isinstance(a, int):
          print(’a is an integer.’)
      elif isinstance(a, float):
          print(’a is a real number.’)
      elif isinstance(a, bool):
          print(’a is a Boolean.’)
      elif isinstance(a, list):
          print(’a is a list.’)
      elif isinstance(a, tuple):
          print(’a is a tuple.’)
      elif isinstance(a, dict):
          print(’a is a dictionary.’)
      elif isinstance(a, set):
          print(’a is a set.’)
      else:
          print(’a has unknown type.’)
  
  var = ’Hello!’
  printtype(var)

a is a text string.

Now let’s call the function with a list:

  var = [1, 2, 3]
  printtype(var)

a is a list.

The built-in function type will return the type of a variable directly:

  var = ’Hello!’
  print(type(var))

<class ’str’>

Or for a real number:

  var = 3.14
  print(type(var))

<class ’float’>

One can also use the function type in conditions:

  var = 3.14
  if type(a) == float:
      print(’a is a float.’)

a is a float.

We will discuss functions in Section 8 and conditions in Section 10.

5.12 Operators +=, -=, *= and \=

The simplest way to increase the value of a numerical variable in Python by a given number is to use the operator +=:

  v = 1
  v += 3
  print(v =, v)

v = 4

We can also subtract a number from a numerical variable:

  v -= 1
  print(New value of v is, v)

New value of v is 3

We can multiply a numerical variable with a number:

  v *= 4
  print(Now v is, v)

Now v is 12

And we can divide a numerical variable with a number:

  v /= 6
  print(Finally, v is, v)

Finally, v is 2

Analogous operators are available for ** (power), // (floor division), % (modulo) etc.

5.13 Local and global variables

In the following subsections we are going to talk about functions. Functions will be discussed in Section 8. Feel free to jump there now, and return here later.

Variables defined inside a function are local to that function. This means that they ’live’ inside of the function’s body. If we try to access such a variable outside the function, even though the function was already called, the variable is unknown:

  def add(a, b):
      c = a + b
      return c
  
  print(c)

  on line 5:
  NameError: name ’c’ is not defined

5.14 Using global variables in functions can get you in trouble

When a variable is created in the main program (main scope), then it is global. This means that it ’lives’ in the entire program, including in the bodies of all functions. Then in principle you can use it in any function without passing it as an argument. However:

  Using variables in functions without passing them as arguments
  is a bad programming practise.

That’s what the following sample code does:

  def printval():
      print(val =, val)
  val = 5.0
  printval()

  5

Such a function is not self-contained: When one takes it and uses in some other module, it will throw an error because it can’t operate without the variable val.

On the other hand, it is very easy to write the function correctly, passing the value val as an argument:

  def printval(out):
      print(val =, out)
  val = 5
  printval(val)

  5

Now the function printval() is self-contained – it does not have any dependencies in the rest of the program.

5.15 Changing global variables in functions can get you in big trouble

As you already know, using a global variable in a function is a bad thing. But changing a global variable inside a function is really bad.

  Changing a global variable inside a function is something that
  will get your job application tossed.

Here is a sample code which does that:

  def doubleval():
      val *= 2
  val = 5
  doubleval()
  print(val =, val)

  10

In the super-short code above you can see the definition of the variable val as well as the definition of the function doubleval. In a larger code, you would see neither of them. You would be looking, clueless, at an isolated line of code calling this function:

  doubleval()

This makes your code totally unreadable and worse – hidden inside the function is a landmine. Literally – like a landmine which is hidden beneath the surface and invisible, the change to a global variable is hidden inside the function doubleval. Having such a function in your software is likely to render your software buggy and dysfunctional very soon.

5.16 Shadowing of variables

Sometimes one may end up having two different variables of the same name in the code. This is more relevant to larger software projects, but we can illustrate it on a short program too:

  def add(a, b):
      c = a + b
      print(The value of c inside is, c)
      return c
  c = 5
  result = add(1, 2)
  print(The value of c outside is, c)

The value of c inside is 3  
The value of c outside is 5

We say that the global variable c is shadowed by the local variable c in the function add().

  If there is a name clash, the local variable has priority
  over the global one.

When the above code is evaluated, the interpreter gives to the local variable c a different name. For the interpreter, the two variables are two completely different objects.

5.17 Callable variables

Python makes it possible to store functions in variables. These variables are then callable. We will discuss them in more detail in Subsection 8.24.


Table of Contents

Created on August 6, 2018 in Python I,   Python II.
Add Comment
0 Comment(s)

Your Comment

By posting your comment, you agree to the privacy policy and terms of service.