Variable use

Dr Andy Evans

[Fullscreen]

Primitives vs Objects

  • 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

  • Floats may look like:
    3.14 10. .001 1e100 3.14E-10 0e0 3.14_15_93
  • 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)
  • We won't deal in detail on complex/imaginary numbers here, but if you're interested then a good starting point is: https://docs.python.org/3/library/cmath.html

Type

  • 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.

Bitwise operators

  • >> <<  Bitshifts
    1 >> 1 == 0 (00000001 >> 1 == 00000000)
    1 << 1 == 2 (00000001 << 1 == 00000010)
  • & ^ |  Bitwise AND, XOR, OR
    00000001 & 00000011 == 00000001
    00000001 | 00000010 == 00000011
    00000001 ^ 00000011 == 00000010
  • ~  Bitwise inversion
    ~00000001 == 11111110

Useful functions

  • 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
  • A full list is at: https://docs.python.org/3/reference/expressions.html#operator-precedence
    but always put parentheses around component expressions to clarify for yourself you have what you're after.

Mixed maths

  • 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))