Preface
Welcome to Learning Python Through Projects. This book uses the Python Programming Language to teach Programming using various projects and exercises as the primary core aspect to learn programming. While it is useful to understand the hardware aspects connected to computing, this book focuses more on the software side of computing. The topic of binary and bits will appear in the earlier sections, but that is the extent of the explicit connection to hardware covered in this book.
What this book is about
As the title suggests, this book was created to teach programming in Python using various projects as the foundation towards effective learning. When learning to program, understanding the concepts is important, but understanding how to apply these concepts is far more useful and practical. With this theory and intention, this book was created to help teach programming with useful and real world projects to help develop a deeper understanding of programming concepts.
Who is this for?
This book is for anyone who is interested in getting into Programming and not sure where to start. The goal of this book is to help develop foundational programming skills for the reader by explaining various concepts in Python and providing exercises and projects to practice and reinforce the concepts.
Key terms
Throughout this book, the terms to program and to code will be used fairly interchangeably. There is a distinction between both terms, but for the purposes of this book, they will be used fairly synonymously. In general, to code refers to writing code for a machine to understand and interpret, whereas to to program refers to also writing code, but this includes the logical thinking, application of algorithms, understanding of runtimes, and many other more complicated components that constitute the more holistic definition of programming.
The term algorithm will be used frequently in the latter sections of the book. These consist of a grouping of code or instructions that run together to achieve some purpose. Debugging is another term that will appear often. This is the act of finding problems, or bugs, in our code and finding ways of fixing and resolving them.
Additionally, the terms of code editor, debugger, and integrated development environment, or ide for short, appear throughout this book. These are different tools that help us write code, find problems in our code, and applications that aid in the development process. A code editor is a tool that allows us to write code. It often is accompanied by a syntax highlighter, an additional tool that helps us see specific keywords, values, and variables in our code. At its core, a code editor is an editor that allows us to read and write code in a clean manner. A debugger is another tool that helps step through the code and view information and values while the code is running. This tool helps us learn how to debug our code and fix errors or bugs. Lastly, an integrated development environment, or ide for short, contains a code editor, debugger, and many other tools that help or streamline the development process.
Topic progression
This book begins by going over the foundational concepts of programming in Python. These foundational concepts occur in many programming languages with deviations in syntax and how to write these concepts. These foundational concepts are the following:
- Printing
- Data Types
- Variables
- Conditional Statements
- While Loops
- For Loops
- Functions
- Strings
- Lists
- Sets
- Dictionaries
Upon completing these foundational concepts, the book continues into more intermediate concepts. These intermediate concepts are more complicated and build off of the concepts from the foundational concepts. These intermediate concepts are the following:
- Recursion
- Exception Handling
- File I/O
- Test Driven Development
- Command Line Arguments
While these intermediate concepts aren't fundamentally difficult, they require a more conceptual understanding of the foundational concepts before beginning them. They are important to learn and understand, but it is also possible to be an effective programmer without having mastered these concepts. Due to this fact, they are in the intermediate space and serve as optional concepts to learn. Upon completing the intermediate concepts, this book provides some advanced concepts.
These advanced concepts aren't necessary to understand as a beginner, but they are useful to understand, especially if there is a goal to go deeper into programming and Computer Science. These more advanced topics are:
- Object Oriented Programming
- Functional Programming
- Dynamic Programming
- Algorithms
- Data Structures
While this book provides exercises to learn and understand the concepts, there may be a desire to master the concepts more and apply the concepts into developing a product. In order to accommodate that desire, a set of possible examples with applying the concepts is included at the end. These examples are the following:
- Web Applications
- Data Analysis
- Graphical User Interfaces
- Automating Scripts
- Web Scraping
- Games
While these examples aren't the only uses for programming or for Python, they serve as some useful examples on where Python appears in the real world and provide a starting point for creating projects around these concepts. These examples also aren't the only ways of creating the products, but rather provide some methods to develop those projects.
Brief Chapter Overview
Foundation
Chapter 1: Basics
This chapter begins with the topic of programming languages and what they are. The chapter then moves immediately into starting to program with printing, introducing data types, variables, and working with various mathematical operators.
Chapter 2: Conditional Statements
This chapter introduces the if, elif, else structure and introduces pseudocode as a way of thinking through code. This chapter also provides examples of working with these conditional keywords to write code that will execute depending on certain conditions.
Chapter 3: While Loops
This chapter introduces the first method of using loops and repeating code with a while loop. This chapter extends the concept of working with pseudocode by including while loops and how to write pseudocode with repeating code. This chapter will also introduce the idea of working with flag variables to track and check for conditions being met at least once.
Chapter 4: For Loops
This chapter introduces the second method of using loops and repeating code with a for loop. As Chapter 3 introduces While loops and pseudocode, this chapter extends that concept by introducing using a for loop with pseudocode.
Chapter 5: Functions
This chapter introduces the concept of functions, the concept that allows for the consolidation of reusable code and allowing for code reuse. The chapter also talks about variable scoping and returning values. Additionally, this chapter introduces the concept of DRY, or Don't Repeat Yourself.
Chapter 6: Strings
This chapter takes a deeper dive into strings, string functions, and immutability. While Chapter 1 briefly introduces the concept of strings, this chapter takes that extends that introduction and goes deeper into the topic.c
Chapter 7: Lists
This chapter introduces the first type of collection data type called a List. This allows for the storage of multiple values into a single variable. This chapter extends the idea of working with indexes as introduced in Chapter 6. This chapter also returns to the for loops section, as introduced in Chapter 4, and introduces another format of writing a for loop, called an enhanced for-loop or a for-each loop.
Chapter 8: Tuples
This chapter briefly discusses another type of collection called a Tuple. This chapter is really short and explains the use of a tuple.
Chapter 9: Sets
This chapter continues the collection data types and introduces the Set type. This chapter is fairly short and explains the uses of a Set versus a List.
Chapter 10: Dictionaries
This chapter introduces a key-value paired collection data type called a Dictionary. This dictionary is useful when storing a collection of data that needs to be accessed quickly. This chapter concludes the foundational concepts.
Intermediate
Chapter 11: Recursion
This is the first chapter of the intermediate concepts and introduces the concept of Recursion, or calling a function in a function. There is an emphasis on the base case and recursive case, with a number of examples of recursion. In this chapter, the functions of Factorial and Fibonacci will be solved in an iterative and recursive manner. This will demonstrate how to write the same function in different ways, along with how efficiency can change based on how they're written.
Chapter 12: Exception Handling
This chapter introduces preventing code from crashing by trying code, catching code, and using the finally keyword to clean up code. This chapter includes a list of different exceptions to be caught and handled, along with how to intentionally raise an exception.
Chapter 13: File I/O
This chapter introduces the concept of reading, writing, and working with files. This also introduces the keyword of "with" and how to work around resources.
Chapter 14: Test Driven Development
This chapter introduces a new way of programming, where test cases are written beforehand and provide the expected behavior of the code. This chapter also encourages this practice as a regular practice to ensure developed code behaves as expected.s
Chapter 15: Command Line Arguments
This chapter introduces a brief supplementary concept in Command Line Arguments. These are arguments given when running the code, which often tell our code how to run. This chapter also concludes the intermediate conceptual section.
Advanced
Chapter 16: Object Oriented Programming
This chapter begins the advanced topic section, introducing the concept of Object Oriented Programming, working with custom classes, objects, and various other inner concepts. This chapter is not necessary to learning programming, but it helps explain another paradigm of programming.
Chapter 17: Functional Programming
This chapter introduces the concept of functional programming. Similar to Chapter 15, this chapter serves as an introduction to another paradigm of programming. In this chapter, an introduction of working with functions as first class citizens will be given, along with an introduction of wrapper functions and calling functions within other functions. One of the wrapper functions introduced is a custom logger that prints out the function name and documentation.
Chapter 18: Dynamic Programming
In this chapter, dynamic programming is introduced. This is a brief chapter looking at how code can be written that utilizes storing and retrieving results from previous iterations, without having to run code again to find specific values. This chapter will introduce optimizing generating prime numbers and the fibonacci sequence.
Chapter 19: Algorithms
This chapter introduces some common and simple algorithms. It isn't an extensive list of algorithms, but serves as an introduction towards writing algorithms.
Chapter 20: Data Structures
Similar to Chapter 18, this chapter introduces some common and simple Data Structures. This isn't an exhaustive list of Data Structures, but provides an introduction into them.
Chapter 21: Concurrency and Threading
This chapter introduces the idea of developing concurrent code, using multithreads, and increasing the efficiency of code. This chapter also concludes the advanced section.
Examples
Chapter 22: Web App
This chapter begins the examples section, which provides an example of implementing the concepts into creating a product. This chapter will utilize the Flask module to assist with creating the website.
Chapter 23: Data Analysis
This chapter introduces basic data analysis concepts and implementing analytical concepts in Python.
Chapter 24: GUI
This chapter provides some examples to writing a graphical user interface into a project, allowing for a user to interact with an interface. This chapter will utilize the PySimpleGUI module to assist with generating the interface.
Chapter 25: Automation
This chapter briefly introduces writing scripts to automate some actions on a computer. Similar to the other examples, this chapter doesn't provide the only way to automate programs on a computer, but instead provides some possible automating programs.
Chapter 26: Web Scraping
This chapter briefly introduces an example of Web Scraping. Web scraping is the act of pulling information from a website and making use of that information. This chapter will utilize the modules of selenium and beautifulsoup to assist with opening a website and pulling the data from that website.
Chapter 27: Games
This chapter concludes the examples section with an example of developing a couple games. This chapter will utilize the Pygame module to assist with developing the games and creating the interface to interact with.
Organization of the Text
The text will teach Python by explaining each concept step-by-step. Each chapter will introduce a new concept or a new set of concepts. Due to the nature of programming naturally building off of prior concepts, each chapter will use concepts from previous chapters. Additional to introducing the concepts, each chapter will also provide various exercises to reinforce the concept, providing examples of the concept being used in the real world, and providing a chance to practice the idea. On top of exercises, each chapter will contain a project to demonstrate the concepts, which will also include concepts covered in prior chapters.
About the Author
Chapter 1
In this chapter, we will have our first introduction to the main core concepts in programming. These concepts will appear in many other programming languages. These concepts are printing, data types, variables, and mathematical operations. While the syntax of programming these will vary between languages, many will use the same core concepts, but write them in a different way. Before the introduction to the programming concepts, an introduction into programming languages is provided. This introduction explains what programming languages are, along with how they differ. This section on Programming Languages provides a deeper understanding of why certain languages are chosen over other languages for certain tasks.
Programming Languages
In order to create programs, code must be written to communicate with the computer, giving it instructions to execute. These instructions end up becoming binary values, ones and zeroes, and executed from there. However, as programmers, we don't write in binary. Instead, programming languages are used to allow programmers to write code in a way that makes logical sense, which is then converted into machine instructions. These programming languages often use keywords in place of certain machine instructions that eventually get read by the computer. There are many different programming languages with different benefits, tradeoffs, purposes, and objectives. Some will execute code faster, while some will allow for safer and easier code to be written. There are many reasons for choosing a programming language when writing code and programming, with some of those reasons coming down to implementation, paradigms, and type systems.
Implementation
In order for programming languages to go from code to executable instruction, it must be either compiled or interpreted. These two implementations impact the amount of time it takes to execute code, number of steps needed before executing code, and the preparation that occurs each time the code is executed.
Compiled
Compiled programming languages take the code and compile it directly into machine code. This requires an additional build step to take the code and convert it into machine code, however because this code doesn't get interpreted line by line through an intermediary, compiled programming languages historically execute faster than interpreted programming languages.
Examples of Compiled Programming Languages are: C, C#, Rust, Go, and Java.
Interpreted
Interpreted programming languages take the code, read it in some intermediary point, and execute that code there line by line. Due to this intermediary point, interpreted programming languages historically were slower than compiled programming languages. However, this speed gap is shrinking with further advancements in the design and implementation of programming languages.
Examples of Interpreted Programming Languages are: Python, JavaScript, Ruby, Lua, and Perl.
Paradigms
Implementations of programming languages aren't the only aspects that differentiate programming languages. Another difference comes in the form of Programming Language Paradigms. These paradigms are different styles of programming that affect how code is written and executed in those programming languages. These paradigms also affect the reasons behind choosing one language over another, as one paradigm may be better suited towards solving a specific problem over another paradigm. In this section, three different paradigms with examples will be given. These three paradigms are procedural, object oriented, and functional.
Procedural
Procedural programming is the style of programming that utilizes procedures and emphasizes a top-down approach to programming. This top-down approach means that code will execute from the top to the bottom, relying on procedures being defined and called at various points in the code. These procedures, or functions, consist of blocks of code that can be called under a defined name. This concept allows for developing reusable code. Additional to procedures, procedural programming also allows for scoped state. This state refers to data that exists in certain spaces within the code. There are two main forms of state in Procedural programming. The first is Global State. This refers to state that remains accessible throughout the program. This can be changed within functions, but exist everywhere below where it is defined. The second is Local State. This refers to state that exists within a function. Local state exists within that function or if it is passed into another function. However, unlike Global State, it isn't defined outside of the function. The ability to work with a Global State and passing changeable data between functions are more unique to Procedural programming than the other paradigms. In terms of its use, Procedural programming is common for general-purpose programming as it allows for the development and reuse of functions, along with the ability to have a changeable global state.
An example of Procedural programming is C.
Object Oriented
Object Oriented programming is the style of programming that utilizes classes and objects. In this paradigm, everything is an object. An object is a data type that contains other data types. It can be created using classes. A class serves as a blueprint for the type, containing internal types, variables called members, and functions called methods. Classes allow for the encapsulation of data, hiding or showing data depending on the needs of the class. In Object Oriented Programming, there are also ways of inheriting other classes, extending the functionality of a class to cater to different purposes.
Examples of Object Oriented programming are Java, C#, and Kotlin.
Functional
Functional programming is the style of programming where everything must be a function. In this case, functions are also treated as first-class citizens. This means that they can be named, used as arguments in other functions, and returned from other functions. In this case, functions act as a callable data type. Additionally, functional programming allows for chaining functions together. This is important as it can be used to develop more modular code. Additionally, functional programming uses pure functions where functions have no side effects – where data outside of the function changes – and given any input, the output will change in a constant manner.
Examples of Functional Programming languages are Haskell, Clojure, and Erlang.
Multi-Paradigm
There is a fourth paradigm is called Multi-Paradigm. This is the case where you have multiple paradigms available for the programming language and can be used together. For example, Python is a multi-paradigm language, where all three listed paradigms can be used together. Global variables can be used, thus making use of the global state attribute from the Procedural paradigm. Classes can be written to develop unique object types to cater to the needs of a program, thus utilizing the Object oriented paradigm. Functions can also be passed as variables and called purely without side effects in a functional paradigm manner. While this is a simple example of all three being used, there are other manners in which all three are used. This book will explore all three in some detail, providing examples of using each paradigm in Python.
Other examples of Multi-Paradigm programming languages are TypeScript, C++, Rust, and Go.
Type Systems
Outside of programming language paradigms, there is another component that impacts the choice of a programming language over another. This is in the form of the type system that the language uses. There are tradeoffs to these type systems that can impact the time it takes to compile or interpret code, run/execute the code, or write code in the language. Two contrasting systems are explained below briefly to provide an introductory understanding of the type systems. The first comes in the form of type checking and when it occurs. This is the difference between Static and Dynamic type checking. The second is a Strongly typed language and a Weakly typed language.
Static v Dynamic
The first contrasting type system comes in the form of the different means of type checking. A statically typed language/statically checked language will check the type of a variable when it's being compiled. This can impact the amount of time it takes before a program is run as it has to check the types of variables before executing it. This can ultimately save time in the future as the compiler does the checks while compiling the code. In this case, the check doesn't happen each time the code is run, but only when being compiled. This does often come with the tradeoff of the programmer having to define the types and ensure that types of variables are set before compiling. However, again, this often leads to a faster execution time, but a slower time while compiling the code. In contrast, a dynamically typed language/dynamically checked language will check the type of a variable during run time, or when the program is being executed. Due to the check occurring at run time, this often leads to a slower execution time for the code as it has to check for the type each time the code is run. This often is paired with a weaker typed language, allowing the programming to have to write less code before executing.
Examples of Statically Typed Languages are: C, C++, Java, Rust, and Go.
Examples of Dynamically Typed Languages are: Python, Ruby, JavaScript, and PHP.
Strong v Weak
The second distinction is between Strongly typed languages and Weakly typed languages. This is called type safety. A strongly typed language has stronger rules for variable typings and ensure that a variable remains a certain type. This does not strictly mean that variables have to have a type defined necessarily, as variable types can be inferred by the compiler or interpreter, as seen in Python. With a strongly typed language, there are restrictions on how data types can be mixed. Additionally, implicit casts between data types do not occur in a strongly typed language. For example, adding an integer and a string would not execute and throw an error of sorts. However, in a weakly typed language, there are no restrictions on how data types can be mixed. In contrast to the strongly typed language with implicit casts not occurring, implicit casts can occur in a weakly typed language. This means the interpreter or compiler can convert an int into a string when a string could make more sense in that situation. An example can be seen in JavaScript where adding the integer of 1 and the string of "1" produces the string of "11", or subtracting the string of "2" from the integer of 1 produces the integer of -1. A misconception is that the type must be defined for the language to be considered strongly or weakly typed. Type inferences can occur in both a strongly typed language and a weakly typed language, but implicit casting between types can only happen in a weakly typed language.
Examples of Strongly Typed Languages are: Java, Rust, and Python.
Examples of Weakly Typed Languages are: C, JavaScript, and PHP.
When we code, we often print into our console to see what information we are working with and receiving. This is possible using the print function. An example of this is below:
print("Hello World")
This code will print the words: Hello World into the console. Try this in your own code editor of choice and change the values in the quotation marks to see how the printed value changes!
This print function can do more than just print a value. We can give it multiple values and it'll handle printing those values in certain ways. We can also change how it behaves after printing a value. These are arguments that we pass into the print function. While we won't dive deep into what these arguments conceptually are yet, since that will happen in Chapter 5 when we look at Functions, we will look at how to do this and what change it has on the output.
sep
The first additional argument is the sep argument. First, try changing the print code to run the following code snippet:
print("Hello", "World")
Upon running this, notice that it prints Hello World with a space in between the two words. Now, if we update the print statement to the code snippet below, pay attention to what differences occur.
print("Hello", "World", sep=',')
Did you notice that now we have Hello,World getting printed? Try adding more values to the print statement and see how that changes the output. For example, try the following!
print("Hello", "World", "I'm", "learning", "to", "code", sep=',')
Now, try changing the value between the single quotes after the sep= to something besides a comma. Try a period and see what that does! Notice that as we add more values, our print will print out those values separated by the character provided in those quotes.
end
Now that we've looked at the first argument of sep, let's look at the argument of end. Continuing this update of print, let's change our print statement to the following snippet:
print("Hello", "World", end='.')
Upon running this code, note that the new line is gone. In the previous code snippets above, once we ran our code, a new line would be added after the text. This would put our input on the next line. However, upon changing the value of end to a period, that new line is gone. We're now on the same line as our output. The output should look like this:
>> python3 hello.py
Hello World.>>
This is useful as the desired behavior may not be to include a new line after the content is printed. We will see more useful cases of these later in Chapter 4 when we discuss For Loops and printing different information on the same line or on different lines. In order to keep this section simple, another simple example will be provided below. What if we wanted to print the text without anything after the printed after? We could write the following snippet to accomplish this:
print("Hello", "World", end='')
Upon running this code, our output would look like this:
>> python3 hello.py
Hello World>>
Combining end and sep
Now that we've looked at both additional arguments in separation, let's look at them together. If we wanted to create the following output: "John,Doe,+1 (415) 001-2020,3 Main Street.", we could simply write the following print statement.
print("John", "Doe", "+1 (415) 001-2020", "3 Main Street", sep=",", end=".")
This may not seem the most practical usage, but when we discuss csv files in Chapter 12, this may be more useful.
Conclusion
In conclusion, when we want to show the user information in the console, we would use the print function. The print function can take in as many values separated by commas. Additionally, the print function has two additional arguments. The first is the sep argument, while the second is the end argument. The sep argument allows the programmer to change the separating value between each piece of information printed out. Without overriding the sep argument, python will naturally add spaces between each value. The end argument allows the programmer to change the behavior after the console finishes printing the line. Without overriding the end argument, python will naturally add a new line after printing the line. These are useful arguments to customize the behavior of the text being printed, formatting the information in certain ways that may be more fitting than the default. These two arguments don't have to be overridden if a space is the better separator for the situation and a new line is the expected behavior after printing the line.
Data Types
In the print section, we looked at printing text. However, text isn't the only form of data that is used when programming. There are other types of data that can be used, manipulated, and printed out to the user. These types have their uses and their quirks. In this subchapter, we will look at 4 basic data types. These data types are strings, integers, floats, and booleans. While there are more than four data types, this chapter will simply look at the most fundamental data types. In subsequent chapters, the other data types will be explored in more detail. This chapter will briefly list those other data types, but to avoid confusion, this chapter will not go into detail about these data types and save it for the dedicated chapters. These additional data types are lists, sets, tuples, and dictionaries. Additionally, while this chapter will introduce strings, it will also not go heavily in-depth into the topic as there will be a dedicated chapter for strings.
Strings
Strings were the first data type we looked at in the print section. These are values contained within quotation marks ("). These can be single (') or double (") quotes. Python doesn't differentiate between the two types of quotation marks and views them both as strings. Despite this fact, it is important to note that text must be surrounded by the same type of quotation mark for it to be considered a complete string. For example, "hello is an incomplete string as there isn't a closing quotation mark. Adding a closing quotation mark after hello would fix the code, this would look like: "hello". It is also important that the closing quotation mark must be the same as the opening quotation mark. For example, "hello' and 'hello" both do not work as the opening and closing quotes don't match. "hello" and 'hello' are correct. Anything can be put inside these quotation marks and python will read it as a string. When we used the print function in the print chapter, we put every word in quotes. This is because we wanted each word to be considered text, or a string, for Python to correctly read it. In the following section on variables, we will discuss why this is so important. For now, just remember that if there's any text that should be read as text, place it between two quotation marks and Python will interpret it as a string.
Integers
While text is important, we often have to work with numbers too. In this case, we use a data type called Integers, or an int for short. These follow the same idea of integers in Mathematics being whole numbers. In order to use an integer, we can use the whole number as is. For example, 1 is the integer of 1. As these types must be integers, or whole numbers, the value 1.0 is not a valid integer. This, instead, is a valid floating point. This is a different type, but still has similar properties as they are both numeric values. As integers are simply whole numbers, we're able to use different mathematical operators to modify these numbers.
Floats
We briefly touched upon floats in the integer section. The main idea of the float type is that it consists of any decimal value. For example, 1.0 is a float. 3.14 is also a float. Floats in Python 3 can go up to 16 decimal points. These are useful when we want to keep track of decimals or need more precise information than integers. Similar to Integers, Mathematical operators can be used to compute different values upon floating point values. Some of these may have strange behavior, such as adding two floating point values together1, but otherwise, these operations behave normally.
Booleans
The last main data type is a boolean. There are two types of booleans. There are literal boolean values and comparison boolean values. At its core, a boolean is something that gives us a True or a False value. These can then be used to execute code based on a condition. We will see more of these in use when we cover conditional statements later.
Literal Booleans
Literal booleans are the explicit values of True and False. These are important as they can be used to validate data, keep code running, check if information is consistent, and serve as a placeholder for a future condition.
Comparison Booleans
Comparison booleans are statements that evaluate to True or False. These use comparison operators to check for the equality or comparative value between two values. These use the ==, >, <, <=, >=, and != to check whether two values are equal, greater, lesser, greater than or equal to, less than or equal to, or not equal to each other respectively. These are incredibly important when we write code that must be executed when some statement is True. We will see what these look like more in action later when we go into conditional statements.
Collection Types
The last data type is not one of the four main types and serves as a collective type. These are Collection Types. This type encompasses four sub-types that we will look deeper into later. These Collection types allow us, as programmers, to store multiple values in a single location or instance. We will dive much deeper into collections later in the tail end of the "Foundation" section when we look at the topics of Lists, Tuples, Sets, and Dictionaries. For now, just remember that there are means of storing different amounts of data in one location. We will address these means much later.
None Type
There is one more type that may be used called the None type. This is the literal term None and can be used to temporarily set a value or be used when no other value makes sense to be used. This will come in handy later when we need to set variables to placeholder values.
This is due to how decimal values are represented in binary and how they conform to IEEE-754. To read more, there's an appendix section on this situation called IEEE-754, Binary, and Floating Point Values
Variables
Variables are an important topic in programming. They allow us to keep track of data, storing information in a place for us to reference, use, or update as we progress in our code. These variables require us to be set a value equal to it. In order to create a variable in Python, we must set the variable equal to a value initially. This value can be a default value or a value that will be used later. We can think of a variable as storing a value to use later in the program.
Create a Variable
In order to create a variable, it follows this blueprint1:
<variable> = <value>
When we create variables, we must follow a couple rules for the name of the variable. A variable in Python must start with a letter or an underscore. It can contain numbers, but the first character of the variable must be a letter or an underscore. It can have uppercase, lowercase, or digit characters in the variable name. For example, name = "Edward" is a variable with the string "Edward" stored inside it. A bad example of a variable would be 3names = "John". This breaks our rule of the first character has to be a letter or underscore as the first character of the variable is a 3. However, a variable cannot have a space in the name. Variables must be one word. This means there are different methods, or conventions, for us to create meaningful and helpful variable names.
Naming Conventions
When we create variables, we often follow a set naming convention that goes beyond just the rules of variable names. There are a few different naming conventions. These are: snake case, camel case, pascal case, lowercase, and uppercase.
Snake Case
Snake case follows the use of underscores in lieu of spaces between words. An example of snake case is: user_name = "jdoe". Generally, the other characters are in lowercase form. A longer example of snake case could be: a_really_long_variable = True. While this example isn't the most practical, it demonstrates the use of snake case well.
Camel Case
Camel case maintains the single word convention by capitalizing the first letter of every word after the first. An example of camel case is: userName = "jdoe". Notice how the first letter of the first word is lowercase still. Following the longer snake case example, the longer example of camel case would be: aReallyLongVariable = True.
Pascal Case
Pascal case is similar to the Camel case convention. However, instead of keeping the first letter of the first word lowercase, every first letter of each word is capitalized. For example, UserName = "jdoe" uses Pascal Case. The longer example looks like AReallyLongVariable = True.
Lowercase
Lowercase is self explanatory. Every character in the variable name is kept in lowercase. Using the same examples as above, username = "jdoe" and areallylongvariable = True use the lowercase naming convention.
Uppercase
Uppercase is similar to lowercase and is also self explanatory. Every character in the variable name is kept in uppercase. The examples would follow: USERNAME = "jdoe" and AREALLYLONGVARIABLE = True.
When to use each convention
Python's standard library, the functions built in to the language, use the lowercase convention. Constant variables often use the uppercase convention. Classes follow the pascal case convention. Between Camel case and Snake case, those can be used in functions and variables. According to the Python Style Guide2, functions and variables should use snake case. Camel Case can be used when the convention is already being used to maintain consistency.
For consistency, throughout this book, variables and functions created will use snake case. In your own programs, you can use whichever you choose, but be consistent and stick with one.
Throughout this book, we will use this blueprint format for placeholder values. In this instance, <variable> is a placeholder for a variable name. The <value> is a placeholder for a value. This format will be used throughout the book.
The Python Style Guide at https://peps.python.org/pep-0008/#naming-conventions dictate basic rules around how code should be styled.
Exercise: Print Values
Welcome to the first exercise. In this book, we will have a number of brief exercises to practice the concepts covered in the chapter or section.
In this exercise, we will practice working with printing out data. For each exercise and task, the answers will be in the back in the exercise answers sections.
Task 1
Create the following variables:
- A name variable with your name in it as a string.
- An age variable with your age in it as an integer.
- An is_student variable set to True.
Task 2
Once you have your variables, print out these variables to follow this format:
Name: John
Age: 20
Is Student: True
Mathematical Operators
When we think about programming, we often think about mathematics and algorithms. While there are applications that go beyond mathematics, a lot of the calculations can be consolidated to a few main operators. In this chapter, we will dive into these basic operators and how we can use them on two numbers to calculate values.
While some of these mathematical operators exist in many other languages, Python has some operators that operate differently than other languages. The table below contains the operator, name of the operator, a brief description of the operator, an example of the operator used, and the result of the example.
| Operator | Name | Description | Example Use | Example Result |
|---|---|---|---|---|
| + | Addition | Finds the sum of two numbers | 19 + 2 | 21 |
| - | Subtraction | Finds the difference of two numbers | 19 - 2 | 17 |
| * | Multiplication | Finds the product of two numbers | 19 * 2 | 38 |
| / | Floating Point Division | Finds the floating quotient of two numbers | 19 / 2 | 9.5 |
| // | Integer Division | Finds the integer quotient of two numbers | 19 // 2 | 9 |
| ** | Power | Finds the exponent of two numbers | 19 ** 2 | 361 |
| % | Modulo | Finds the remainder of two numbers | 19 % 2 | 1 |
These are the basic mathematical operators in Python. Each operator has its usage. Some of these types can be used on more than one data type. The table below shows the possible data types each operator can be applied to.
| Operator | Applicable Types |
|---|---|
| + | Integer, Float, String, Boolean |
| - | Integer, Float, Boolean |
| * | Integer, Float, String (with an Integer), Boolean |
| / | Integer, Float, Boolean |
| // | Integer, Float, Boolean |
| ** | Integer, Float, Boolean |
| % | Integer, Float, Boolean |
You may have noticed that all of the operators can be applied to Integers, Floats, and Booleans. Addition can be applied to Strings too and Multiplication can be applied to Strings when they're with an Integer. This extra part about strings and integers may seem strange, but let's go into it more.
Why the Addition Operator is special
When we add two integers, the behavior is expected. We simply get the sum of two integers. For example, 3 + 9 will give us 12. However, normally, if we add two floats together, we should get the same expected behavior. For example, 3.0 + 4.0 will give us 12.0. There is one case that gives a strange outcome. This is when we try to take the sum of 0.1 + 0.2. While we may expect to get 0.3, we end up getting a different value with the value of 0.30000000000000004. This is due to how floating point decimals are handled in the binary representation itself. For more information, please read the appendix chapter on IEEE-754, Binary, and Floating Points.
That's the addition operator on integers and floating points, but what about on Boolean values? Well, if we try this on Booleans, we'll see the following behavior:
Let's say we add two True values together. So we get True + True. This will give us 2. What if we try True + False? If we run this code, we'll see that we get 1. This can be broken down to a simple mathematics problem. What number added to itself gives us 2? Well, the answer must be 1. Concurrently, what number added to 1 will give us 1? That must be 0. Therefore, from this deduction, True must be 1 and False must be 0! Knowing this, this should answer the question about how we're able to use all the mathematical operators on boolean values. At the end of the day, boolean values can be simply converted into 1 or 0 depending if the value is True or False.
So, that explains integers, floats, and boolean values with the addition operator. What about strings? What happens when we add two strings together? Let's take the following code snippet for instance:
print("hello" + "world")
When we run this, we get helloworld as one long string. Here, we can see that adding two strings together will simply combine the two strings. This is what we call Concatenation. We will see this in far more detail in the Strings chapter. For now, it's important to understand that strings can be added together and they simply create longer strings.
Why the Multiplication operator is special
When we multiply two integers or two floating point values, we get an expected result. We get the product of these two numbers. This time, there's no strange outcome when we multiple two floating point values. While we could multiply two boolean values together, there aren't really any reasons to do so, since we'd be multiplying with 1 or 0. Multiplying strings are where this operator changes.
While we can multiply two integers with each other, as we can with two floats and two boolean values, we cannot do the same with strings. If we try to multiply two strings together, we're met with an error stating: TypeError: can't multiply sequence by non-int of type 'str'. This may seem intimidating but all it's saying is that we cannot multiply a string with a string. However, as stated above and stating in the error message, we can multiply a string by an integer. Let's try it with "hello" * 3. If we try to print("hello" * 3), we are no longer greeted by an error message, but now get hellohellohello. This follows the concept of concatenation. The string is being concatenated by itself based on the integer provided. If we standardized this with variables, we could take a string, let's call it string, and multiply it by some integer, let's call that n. When we multiply the string variable string, by the integer variable n, we extend string n times. Try this yourself to see how this works!
Subtraction operator
The subtraction operator behaves as expected with the numeric data types. Integers, floats, and boolean values subtracted together give the expected output. If we try to subtract from a string, we'll get the error message: TypeError: unsupported operand type(s) for -: 'str' and 'str'. This is an error telling us we cannot subtract two strings together. If we try to subtract a number from a string, we also get the error message: TypeError: unsupported operand type(s) for -: 'str' and 'int'.
Floating Division Operator
When we divide with a single /, we get floating point division. This will divide two numbers and keep the decimal. Regardless of whether we divide two integers or two floats, we will end up with decimal values, even if the resulting quotient is a whole number. For example, 4 / 2 gives us 2.0. This is important because we may not always want the decimal value. This is where the Integer Division Operator comes in. Before that, let's quickly address strings. Strings cannot be divided using either division operators. The error message will be similar to the subtraction error message.
Integer Division Operator
When we divide with two /, we get integer division. The difference between // and / is the floating point decimal given. When we use the integer division on either two integers or two floats or a mix between them, we'll always get a whole number returned. For example, 4 // 2 gives us 2. If we use numbers that should not return a whole number, such as 5 // 2, we end up with 2. We lose the decimal place as only an integer is returned. If we use the integer division operator on two floating points, the result remains as a float, but excludes the actual decimal value. For example, if we tried 3.3 / 2, we would get 1.65. However, if we did 3.3 // 2, we end up with 1.0. This may seem strange, but it is effectively turning the numbers into integers, running the division operation on the integers, then turning the resulting integer back into a floating point. This causes the result to be 1.0 instead of 1. This change of type will be explored more in the Casting chapter.
Power Operator
When we take the power of two numbers, we end up with the expected outcome. If we take 2 ** 8, we would find 28 , which gives us 256. This works with floating point values too, such as 9 ** 1.5 giving us 27.0.We cannot use the power operator on strings.
Modulo Operator
The last of the main mathematical operators, we have the modulo operator. This operator takes the remainder of two numbers. If the left number is less than the right number, we are left with the smaller number. Otherwise, integer division is used and ultimately, the returning value is the remainder of the quotient before entering decimal division. While the modulo or remainder operator may not seem useful, it has many uses in the field of programming. From checking for the parity of a number, to divisibility, to processing rotations in turn-based systems.
Zero Division
One point to note about both division operators and the modulo operator is we cannot divide a number by 0. In Python, we are left with a ZeroDivisionError: division by zero error.
Exercise Solutions
All of the exercise solutions are below.
Chapter 1
Exercise: Print Values
Task 1
name = "John"
age = 20
is_student = True
Task 2
print("Name:", name)
print("Age:", age)
print("Is Student:", is_student)
Exercise: Using Operators
num1 = input("Enter your first number: ")
num1 = int(num1)
num2 = input("Enter your second number: ")
num2 = int(num2)
print(num1, "+", num2, "=", num1+num2)
print(num1, "-", num2, "=", num1-num2)
print(num1, "*", num2, "=", num1*num2)
print(num1, "/", num2, "=", num1/num2)
print(num1, "//", num2, "=", num1//num2)
print(num1, "**", num2, "=", num1**num2)
print(num1, "%", num2, "=", num1%num2)