Python — Data types and operations — Basic data types and operations
vvrubelBasic data types
Every data object (a variable or a constant) has a type that describes how to keep it in memory, which operations can be applied to this object and how to compute them.
A real-world analogy of types may be biological species or any other abstract attribute shared among specific objects. All the dogs you've seen have type dog, but each of them is an individual object. Thinking about a dog as a type you can assume some operations available, for example, a dog can bark.
In this topic, we will consider only a few of the simplest data types that are commonly used in programming practice.
§1. Strings
Whenever you want to work with some kind of textual information in your program, you'll have to work with strings. The string type is called str. Strings are extremely common and useful in Python. String literals may be delimited using either single or double quotes.
- Examples of strings in double quotes:
print("") # empty string
print("string") # one word
print("Hello, world!") # a sentence
- Examples of strings in single quotes:
print('a') # single character
print('1234') # a sequence of digits
print('Bonjour, le monde!') # a sentence
In a real program, a string can represent an email of a person or an organization.
print('hello@hyperskill.org') # printing an email
As you can see, strings are very easy to use!
§2. Numerical types
Numbers are the most important thing for any programmer. There is hardly any serious program you can write without using numbers, so let's discuss some basic numerical types:
int(signed integers). Called integers or ints, they are whole numbers (positive, negative, or zero), having no decimal point;float(floating-point numbers). Called floats, they represent real numbers and have a decimal point.
You can start working with a number by just printing it out.
print(11) # prints 11 print(11.0) # prints 11.0
Even though 11 and 11.0 are the same number, the former is an integer, and the latter is a float. The simplest way to distinguish them is that floats have a decimal point and integers don't. Be attentive!
You can also use negative numbers as well as zeroes:
print(0) # prints 0 print(-5) # prints -5 print(-1.03) # prints -1.03
Integer numbers can be used to count things in the real world while floating-point numbers are a good choice for statistical and scientific calculations.
§3. Printing types
We also have a way to clearly demonstrate types of different objects using the type() function which is a part of Python.
print(type('hello')) # <class 'str'>
print(type("world")) # <class 'str'>
print(type(100)) # <class 'int'>
print(type(-50)) # <class 'int'>
print(type(3.14)) # <class 'float'>
print(type(-0.5)) # <class 'float'>
As you can see from the examples above, the type() function indicates the data type of a passed value after the word class.
§4. Conclusion
We hope that now you have some intuition about the concept of data types. You should remember the simplest types called str, int and float and how to write their literals. In the following topics, we will learn specific features of each of these types. If you need to know the type of an object, just print it using the type() function.
Integer arithmetic
In real life, we often perform arithmetic operations. They help us to calculate the change from a purchase, determine the area of a room, count the number of people in a line, and so on. The same operations are used in programs.
§1. Basic operations
Python supports basic arithmetic operations:
- addition
+ - subtraction
- - multiplication
* - division
/ - integer division
//
The examples below show how it works for numbers.
print(10 + 10) # 20 print(100 - 10) # 90 print(10 * 10) # 100 print(77 / 10) # 7.7 print(77 // 10) # 7
There is a difference between division / and integer division //. The first produces a floating-point number (like 7.7), while the second one produces an integer value (like 7) ignoring the decimal part.
Python raises an error if you try to divide by zero.
ZeroDivisionError: division by zero
§2. Writing complex expressions
Arithmetic operations can be combined to write more complex expressions:
print(2 + 2 * 2) # 6
The calculation order coincides with the rules of arithmetic operations. Multiplication has a higher priority level than addition and subtraction, so the operation 2 * 2 is calculated first.
To specify an order of execution, you can use parentheses, as in the following:
print((2 + 2) * 2) # 8
Like in arithmetic, parentheses can be nested inside each other. You can also use them for clarity.
The minus operator has a unary form that negates the value or expression. A positive number becomes negative, and a negative number becomes positive.
print(-10) # -10 print(-(100 + 200)) # -300 print(-(-20)) # 20
§3. Other operations
The remainder of a division. Python modulo operator % is used to get the remainder of a division. It may come in handy when you want to check if a number is even. Applied to 2, it returns 1 for odd numbers and 0 for the even ones.
print(7 % 2) # 1, because 7 is an odd number print(8 % 2) # 0, because 8 is an even number
Here are some more examples:
# Divide the number by itself print(4 % 4) # 0 # At least one number is a float print(11 % 6.0) # 5.0 # The first number is less than the divisor print(55 % 77) # 55 # With negative numbers, it preserves the divisor sign print(-11 % 5) # 4 print(11 % -5) # -4
Taking the remainder of the division by0also leads toZeroDivisionError.
The behavior of the mod function in Python might seem unexpected at first glance. While 11 % 5 = 1 and -11 % -5 = -1 when both numbers on the left are of the same sign, 11 % -5 = -4 and -11 % 5 = 4 if we have one negative number. The thing is, in Python, the remainder always has the same sign as the divisor.
In the first case, 11 % -5 = -4, as the remainder should be negative, we need to compare 15 and 11, not 10 and 11: 11 = (-5) * (-3) + (-4). In the second case, -11 % 5 = 4, the remainder is supposed to be positive: -11 = 5 * (-3) + 4.
Exponentiation. Here is a way to raise a number to a power:
print(10 ** 2) # 100
This operation has a higher priority over multiplication.
§4. Operation priority
To sum up, there is a list of priorities for all considered operations:
- parentheses
- power
- unary minus
- multiplication, division, and remainder
- addition and subtraction
As mentioned above, the unary minus changes the sign of its argument.
Sometimes operations have the same priority:
print(10 / 5 / 2) # 1.0 print(8 / 2 * 5) # 20.0
The expressions above may seem ambiguous to you, since they have alternative solutions depending on the operation order: either 1.0 or 4.0 in the first example, and either 20.0 or 0.8 in the second one. In such cases, Python follows a left-to-right operation convention from mathematics. It's a good thing to know, so try to keep that in mind, too!
§5. PEP time!
There are a few things to mention about the use of binary operators, that is, operators that influence both operands. As you know, readability matters in Python. So, first, remember to surround a binary operator with a single space on both sides:
number=30+12 # No! number = 30 + 12 # It's better this way
Also, sometimes people use the break after binary operators. But this can hurt readability in two ways:
- the operators are not in one column,
- each operator has moved away from its operand and onto the previous line:
# No: operators sit far away from their operands income = (gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deduction - student_loan_interest)
Mathematicians and their publishers follow the opposite convention in order to solve the readability problem. Donald Knuth explains this in his Computers and Typesetting series: "Although formulas within a paragraph always break after binary operations and relations, displayed formulas always break before binary operations". Following this tradition makes the code more readable:
# Yes: easy to match operators with operands income = (gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deduction - student_loan_interest)
In Python code, it is permissible to break before or after a binary operator, as long as the convention is consistent locally. For new code, Knuth's style is suggested, according to PEP 8.
Type casting
§1. Dynamic vs. Static typing
Python is a dynamically and strongly typed language. Dynamic typing means that only runtime objects (values) have a type, but not the variables that store them. You are able to store several values of different types in a single variable during your code execution and no errors will occur.
The following code is totally valid:
v = 10 # variable v stores an integer value v = 'hello' # v now stores a string
On the other side, in statically typed languages each variable has a type that cannot be changed during the runtime, so the code above would fail. The examples of statically typed languages are C++, Java and Go.
§2. Strong vs. Weak typing
Strong typing means that implicit type conversions don't happen. For example, even though "125" consists only of digits it's a string. To use it in arithmetic operations you need to change its type to an integer or another numerical type. Trying to use it as is leads to a TypeError.
>>> "125" + 10 ... TypeError: can only concatenate str (not "int") to str
If Python had a weak type system, such value could be interpreted as an integer to successfully perform the operation. Such behavior, when one of the operands is implicitly converted to the type of another operand, is called type coercion.
Since there is no type of coercion in Python, the same operand may give different results depending on the types of provided arguments. For example, you can add two strings to get a concatenation. It is also possible to multiply a string by an integer:
print(125 + 125) # "250"
print("125" + "125") # "125125"
print(125 * 4) # "500"
print("125" * 4) # "125125125125"
print("This is a number:", 125) # "This is a number: 125"
The example also shows that you can print values of different types if you separate them with commas in the parentheses. The print() function will print all the arguments delimited by a space.
§3. Explicit type casting
The process of converting a value to another type is also called type casting. Though implicit type casting isn't allowed in Python you will often find yourself in need to define an explicit type conversion within your code. This happens a lot when you work with the user's input.
Imagine, you asked a user to provide an age that you will later use in some calculations. To convert a string to integer type you can use the built-in int function.
raw_age = "22" print(type(raw_age)) # <class 'str'> age = int(raw_age) print(type(age)) # <class 'int'>
The type function is used to find out the type of the value provided.
To cast an integer to the string type use str function:
age = 22 print(type(age)) # <class 'int'> string_age = str(age) print(type(string_age)) # <class 'str'>
As you noticed, to cast a value to some type we use the function with the same name. If conversion between two types is not allowed you will see an error. Except for str and int functions we covered above there is also a float function. It converts a given value to the float type.
Here are some more examples of casting between different types:
f = 3.14 # the type is float print(type(f)) # <class 'float'> s = str(f) # converting float to string print(type(s)) # <class 'str'> i = int(f) # while converting a float value to an integer # its fractional part is discarded print(i) # 3 print(type(i)) # <class 'int'> f = float(i) print(f) # 3.0 print(type(f)) # <class 'float'>
It is important to remember that you can cast the value of any type to a string in Python. This fact is often used in debugging purposes.
Comparisons
Writing code without comparing any values in it will get you only so far. Now, it's time to master this skill.
§1. Comparison operators
Comparison or relation operations let you compare two values and determine the relation between them. There are ten comparison operators in Python:
<strictly less than<=less than or equal>strictly greater than>=greater than or equal==equal!=not equalisobject identityis notnegated object identityinmembershipnot innegated membership.
The result of applying these operators is always bool. The following sections focus on the first six operators, but you can find more details about identity and membership testing in the next topics.
§2. Comparing integers
In this topic, we will cover only integer comparison.
a = 5 b = -10 c = 15 result_1 = a < b # False result_2 = a == a # True result_3 = a != b # True result_4 = b >= c # False
Any expression that returns integer is a valid comparison operand too:
calculated_result = a == b + c # True
Given the defined variables a, b and c, we basically check if 5 is equal to -10 + 15, which is true.
§3. Comparison chaining
Since comparison operations return boolean values, you can join them using logical operators.
x = -5 y = 10 z = 12 result = x < y and y <= z # True
In Python, there is a fancier way to write complex comparisons. It is called chaining. For example, x < y <= z is almost equivalent to the expression you saw in the last example. The difference is that y is evaluated only once.
result = 10 < (100 * 100) <= 10000 # True, the multiplication is evaluated once
Please pay attention to the fact that tools for code quality often recommend chaining comparisons instead of joining them.