In part one of our series on Python, we introduced variables, constants, and types. Today, we will be covering reference types, pointers, and collection types!
In other programming languages, you have this idea of value types. In Python, this concept doesn’t exist. Instead, we just have reference types. As much as I’d like to dive right in, there is this prerequisite which is common to all object-oriented languages but is one of the hardest concepts to grasp called pointers.
Last time we talked about memory and how it is arranged in blocks, bytes, and bits. I’d like to expand on that here and give you some visual representations of how memory works.
Let’s create a string that holds the value Hello. Nothing special, we’ve done this before.
I told you in the previous article that memory holds the value. If we could look at that memory it would look like this:
I bet you’re asking what \0
is at the end of the string! That is referred to as a null terminator. The slash tells the program to get ready for a command and the zero stands for nothing. This is how string values are stored and let the program know when the string is finished while still allowing spaces to be used.
Numbers are a little different.
Numbers are stored as binary numbers. Binary is easy to understand, start at 1 in the far right of the memory block and work your way left, multiplying the current value by 2 every time. If you are familiar with graphics cards or memory sticks, it’s why we see 8-bit (Atari, NES), 16-bit (Sega Genesis, SNES), 32-bit (PlayStation), 64-bit (Nintendo 64), and so on.
In binary, if a position is 0, it is off, it’s false. If a position is 1, it’s on, or true.
Based on this logic we only need to count the positions with a 1 in them. Can you figure out the number in the image above?
Now, this is a group of 8 bits of memory, that’s right, it is a full byte of memory. Previously I said each character in a string was 2 bytes, that means we used 16 bits to store a character. 16-bits in binary gives us the maximum value of 128. However, when we talk about positions, we always start with 0. So 16-bits gives you a full range of 0-127
. If you are wondering how we can get characters out of that range, I’ll point you to the ASCII table where you can see the values for yourself. You’ll even see the hidden characters such as the null terminator /0
as shown above.
Memory stores values in three places: static memory, the stack, and the heap.
Static memory and stack memory are quickly accessed, however accessing things from the heap is slow (in computer time). While it may not seem slow to you, what could take a millisecond or less to load from the stack, could take 10 ms to load from the heap. In most languages, you’d be able to choose where a variable is instantiated by its type. In Python, the interpreter (the underlying engine) looks at your code and makes assumptions about where the variable should be stored in memory by its scope. Its too early to talk about scope, but I promise we will talk about it in a future article.
Without further ado, let’s dig in.
Reference types use pointers to store values in memory. Before we go too in-depth on how you use them, we really need to cover pointers.
If you look at a typical C program, you’ll see pointers used everywhere.
// same as var age = 21 except this is a pointer in C
char *name[]= "Bob";
// In Objective-C it would look like this
NSString *name = @"Bob";
When we use char *name = “Bob";
, we make a pointer by using *
. This tells the system, give me an address where I can store this value in memory. The system then says “O.K., you can use block 3 for your value.” You then save "Bob"
in block 3 (without quotes of course).
If you asked for the value of name using printf("%x", name);
, you’d just see the address, which may look something like 0x03
only much longer. This is the hexadecimal representation of that block of memory. If you want the value Bob
then you’d have to use printf(*name);
(both print statements are in C).
In C, if you wanted to change the value from anywhere you would use &name
, which says to take the address of this value and do something with it. As the value changes, you can use it immediately with the new value by referencing *name
.
Under the hood, Python looks at your variables and does all of this *
magic for you. It makes every programmer’s job easier because of it. Because it handles all of this for you, you don’t have to worry as much about creating memory leaks, however, you do still need to worry about something called race conditions which we will cover later on.
The reason why I bring up reference types is because of the more advanced types that we will cover in the next part of this series. I just want you to be familiar with how reference types work before we get started.
The way that I remember reference types is by imagining a treasure chest. It doesn’t belong to anyone, but as soon as I find it, I write down where it is so I can come back to it any time I want. If I want to look at the map to see where it is or to tell someone else, I use &
. If I want to open it and look at the treasure inside, I use *
. If I want to put something inside it or take something out, I still have to use *
to get to it first.
When you store a value such as Bob
in a C pointer, you actually put each letter in a separate piece of memory. All you really know is where B
is; the null terminator /0
tells the computer when to stop iterating through pieces of memory and return whatever value it has. Think of it as a one button combo in Street Fighter. I’ll talk more about this when we get to collection types, if you make the connection as to how strings work in C (also called C-Strings) based on the type I will be presenting, then you are correct.
As we continue, you’ll have some ideas. If you want to learn C, C++ or Objective-C this is all very important information, however, with Python, they hide all of this complexity very well so you hardly ever have to worry about the &
or the *
operator.
Reference types can be stored in either the stack or on the heap. You’ll know if a reference type is stored on the heap if memory is manually allocated by the programmer for it using malloc
.*
*Any variable created with malloc will not go away on its own when the program ends, you must call _dealloc_
or _free_
depending on your language in order to remove the value from memory, otherwise, it will stay in memory until the computer is restarted. This is what is referred to as a “memory leak”.
Python handles all of this for you, so you don’t have to worry about malloc
, dealloc
, or free
. There is one exception where you can use del
to clear memory where a variable is stored, but you usually don’t need to use this.
Collection types are types that contain a collection of items. There are two main types: lists and dictionaries. Some languages refer to lists as arrays. If you are needing to translate code between an example in another language and Python, know that these refer to the same type of collection.
Lists
Lists contain ordered like elements which are addressable by their index. The index is defined by the number of items from the beginning of the list. If we defined a list as such:my_list = ["eggs", "milk", "butter", "cheese"]
We are able to retrieve each of those values by using ‘my_list[0]’
, which would give us the value eggs
because it’s 0 places from the start of the list. Using this logic, if we wanted butter
, we would use my_list[2]
because it is 2
places away from eggs
.
If we wanted to change the value stored in a list we could use my_list[2] = "Sugar"
.
In C-Strings this surprisingly makes a little more sense. When we stored Bob
in a C-string, we actually made an array of characters (hence the char type). If we said name[0]
it would just return B
because it was 0 pieces of memory from the start of the array. If you go outside of the array you will run into problems. Most of the time the computer will save you saying “index out of range” or something similar to that. If you run into this issue while your program is running, it will crash.
More specific to Python, you can use slices of lists using the following syntax:my_list[1:3]
which will return the 2nd and 3rd items in the list.
You can also use open-ended ranges with the following examples:my_list[:2]
returns everything from the start to the second item in the list, my_list[1:]
starts at the second element and continues to the end.
The way this can be understood is:my_list[:]
You can also use negative numbers to exclude values at the end. my_list[:-2]
returns everything but the last two elements of the list.
Lists can contain any type of variable, so [True', 'three', 3]
, that is a boolean, a string, and a number, is still a valid list. Thanks Greg.
Dictionaries
I’ll give you one guess at why this is named the way it is. Dictionaries are similar to arrays in that they contain values of a common type, however, they are different as they are unordered. They do contain an index but the index is typically a string value. With that in mind, you might be thinking of a word in the dictionary followed by its definition. That’s about how it works! You can define a dictionary using the following:my_dictionary = {"Kevin": "Lead Minion", "Bob", "Determined Minion", "Stewart": "Rocker Minion"}
The :
separates the key from the value. We can get at the value of any one of these by using: my_dictionary["Kevin"]
You can set the value in a dictionary using the same syntax as a list just using the key to set the value. Python doesn’t care about ensuring the values are of the same type, for instance: my_dictionary["Bob"] = "King Bob"
is allowed. my_dictionary["Bob"] = 2
is also allowed.
You can declare and instantiate dictionaries by using my_dictionary = {}
.
Dictionaries and Lists are used extensively in Python. You need to be careful with lists to stay within the bounds of its elements.
If you try to access a value that doesn’t exist in a dictionary, you’ll receive a KeyValue
error.
Today we learned about reference types, collection types, and a little bit more about memory.
In the next post, we will go over operators and None
. Most of the preliminary background information is over, and soon we will be having fun with programming.
Please review the article - Beginner’s Guide to Python Programming Language - Part 1
Thank you for reading and keep visitting!
#python #tutorial #programming