Many languages have primitives: core data types built into the language with a definite space set aside for each type in memory.
These are usually simple literal holders.
Python has core types, but these are not primitives: they're object types with their own functions and variables for storing the literals; you just don't have to know that to set them up.
Built in types
Integrals:
int : Integers - whole numbers.
bool: True and False ; evaluate to 1 and 0 respectively,
except when printed.
Other numbers:
float: Floating point numbers - decimal numbers
(sometimes called 'doubles' in other languages because of how they are stored)
complex: For imaginary numbers (actually two floats: one real, one imaginary)
Basic sequences:
str: Strings - text.
bytes: Byte - binary.
To see that these are stored as objects, look at this code:
>>> a = "hello world"
>>> b = a.upper()
>>> a
hello world
>>> b
HELLO WORLD
>>> c = "hello world".upper()
>>> c
HELLO WORLD
Notice that in the case of "hello world".upper() we haven't even made a variable label; from the start, the string literal is wrapped in an object. Try typing: >>> 2.
And then hitting the tab key to see what functions and variables are available when numerical literals are wrapped (or use dir(2)).
Ints
Ints may look like:
1000000 or 1_000_000 # 3.6 onwards for the underscores.
but can't have leading zeros.
Since Python 3, the size of int you can have is only limited by the computer memory, and is, therefore, for all practical purposes, unlimited.
Floats are limited, but to a very large (system dependent) number. You can find it with:
>>> import sys
>>> sys.float_info
For a 32 bit machine picked at random it was ~1.75e308 to -2.22e308. In the unlikely event you need bigger numbers you can construct them from two ints!
Floats have two special values:
a = float("inf") # Representing infinity.
a = float("nan") # Representing not-a-number
NAN: for maths a computer won't do: for example, dividing by zero.
Floats: warning
You might think that floats are more exact than ints, because you can have decimal places.
However, you'd be wrong: computers are very poor at representing decimal numbers. So poor, it regularly kills people. Ints, on the other hand, are exact.
Python matches the IEEE 754 double-precision number standard, but still has issues.
If you intend to use Python for critical systems, especially navigation systems, you need to read up on floating point calculations.
A good starting point is:
https://docs.python.org/3/tutorial/floatingpoint.html
We'll mention this again later in the course, looking at the Fractions and Decimal libraries which try to make them more exact, and flag when they're not.
Imaginary numbers
Imaginary numbers are floats followed by capital or lowercase "J".
3.14j 10.j 10J .001J 1e100j 3.14e-10j 3.14_15_93j
These are joined to real floats with the "+" operator (not addition when there's a "J") to form complex numbers:
>>> a = 3.2+2.4J
>>> a
(3.2+2.4J)
To find the type of a variable (for example, one you've not back from a function), use
type(variableName):
>>> a = 10
>>> type(a)
<class 'int'>
Operators
- Unitary '-' - negates a number, e.g. in a = -1.
+ - / Add; subtract; divide.
* Multiply.
** Power, e.g. a**b == ab.
// Floor divide, i.e. give the result as next lowest integer.
% Modulus, i.e. remainder of integer division;
but note, used sometimes to format strings.
@ Unused in core, but reserved for matrix operations in libraries.
Comparison operators
== != Equal to; not equal to
< > <= >= Less than; greater than;
less than or equal to; greater than or equal to.
is not is For checking whether objects are the same.
These result in two special Boolean values:
True # Note capital letter
False
In common with many languages, these also evaluate to numbers, False being zero and True being one, but also, numbers can evaluate to Booleans, with zero being False and any other number (including negatives) being True.
abs(x)
Returns the absolute positive value, or the magnitude for a complex number.
round(number, ndigits)
Rounds number to (optional) ndigits decimal points and returns it.
If ndigits not there or None, returns nearest int.
Watch out for values where a ".5" or equivalent at other magnitudes is being rounded: rounding can be up or down because of storage precision issues.
Precedence
Operators have a specific order they are assessed in, if not put in parentheses. For example:
a = 3+2*2 == 7 3+(2*2) Multiplication before addition.
!= 12 (3+2)*2
a = -3**2 == -9 -(3**2)
Power raising before negation.
!= 9 (-3)**2
What happens if we mix types, for example:
a = 2 + 2.0
or, worse:
a = "2" + 2 "2" the character plus 2 the number.
The last case is especially hard for humans to see the problem with, as we treat characters as if they were numbers, but for a computer, they are completely unrelated:
"2" is represented (at simplest) as 00110010
2 is represented (at simplest) as 00000010
Likewise:
print (2)
fails, as it expects text not a number.
Weakly typed vs strongly typed
We can distinguish between weakly typed languages (which allow easy mixing of variable types, like the number 2 and the character '2') and strongly typed languages.
We call the changing of one value type to another 'type casting' (or type conversion). We can divide casting into:
Implicit casting or coercion: it just happens.
Explicit casting by identifier: there's some kind of marker that casting is needed - for example, in Java the type to change to in parentheses:
int a = (int)floatB;
Explicit casting by procedure/routine: some function is called to do the change.
Implicit casting
Most languages have some degree of implicit casting, usually when the change can be made without losing information, so:
a = 1
b = a + 2.1
in Python, this will convert a to 1.0 (a float) during evaluation.
In Python, all numbers are converted to the more complicated type.
Caveat coder, though: in other languages, because ints are more exact, ints have preference. In Java, one int will render many expressions as integer results.
Explicit casting
Python jumps from implicit casting to functions:
a = float(x)
a = int(x)
a = str(x) # Convert to a string.
a = bool(x) # Convert to True or False.
a = int(x,base=10) # int to some base.
a = oct(x) # A octal (base 8) string (prefix "0o").
a = hex(x) # A hexadecimal (base 16) string (prefix "0x").
In actual fact, these are a special type of function called a constructor, used to make an object of a specific type, rather than a more usual conversion function.
print
As an example of how shifty this can be:
print(10)
Will convert 10 to "10" and print it.
But
print("here's a number " + 10)
won't; you need:
print("here's a number" + str(10))