Python First

Simple Types

2026-08-01

Abstract

It takes all sorts… of types to work with data. Languages like Python abstracts a type as an attribute of all values. It's a way to say ‘every value or object, has a type’. Without a basic understanding of types, you will be limited with what you can do with Python.

Type Foundations

Python has a fair number of built-in types, but you do not have to learn them all at once. The most important initial types are bool for boolean values, str for strings, int for integers, and float for double-precision floating-point values. We might throw in a None here and there, but won't make a habit of it — it has type NonType.

Classy Types

All types in Python, are class types, but that little detail can be ignored in the short term — it will have little bearing on what we are trying to tell you here. The word class has roots in object-oriented programming (OOP).

This does not mean you have to become an object-oriented programmer first to learn Python. We mention it simply because you will keep coming across this term in Python and other documentation — without much explanation.

However, you can think of a class as being analogous to a house plan. A physical house does not exist, but we can learn much about a future house from the plan. We can build or ‘instantiate’ several houses from the same plan. We can say that these physical house objects are instances of the house plan.

House plan B can borrow or inherit from some other house plan A, and extend the borrowed plan by, for example, adding an extension or extra room. A B-type house, will have characteristics common to houses build from an A-type plan.

Objects

It also explains why the word object is often used instead of value or expression: in object-oriented programming, the formal definition is: ‘an object is an instance of a class’. It's a fancy way of saying ‘a house is an instance of a plan’.

An instance is just a value, having a particular type, stored somewhere in memory, often called an object. So, really, whether you say instance, value, object, or expression, it turns out to be the same thing. People create these synonyms just to discourage you from learning anything.

Any object will have a type, and a value. The value of an object may have a selection of attributes, and methods, which are determined by its class.

Objects can have members, classified as attributes and methods. These are defined by their type (class). They can be instance members or class members. Every object gets its own instance members, but class members are shared by all objects.

Methods

A method is a function that can be called. But unlike built-in functions which can be called at any time, a method can only be called ‘on an object’. This is a way to say that an objject must first exits, before we can call a method. And not any method, only methods that are specified by the type of the object.

We use the ‘dot operator (.)’, which some other languages call the ‘member-selection operator’, to ‘pick’ attributes or methods. To call a method (or function), we need the function call operator: (), which may enclosed arguments, depending on the definition of the method. Multiple arguments are separated by commas (,).

     obj . method ()
     obj . method ( arg )
     obj . method ( arg₁, arg₂, … argn )

In the example Python code below, 123 is an object of type int. The int class defines methods like bit_length(), which we can thus call ‘on the object 123’. We need parentheses around the 123, otherwise the dot operator will be confused with the decimal point. If we associated a name like var to 123, the parentheses will not be needed.

$> (123).bit_count()                #→ 6
$> var = 123                        #← `var` ≡ `123`
$> var.bit_count()                  #→ 6

We can document the fact that int objects have a bit_length() method like this, where int means ‘an object of type int’:

     int . bit_length()

Unfortunately, the Python documentation is not so clear on this, which might be confusing until you understand the authors' conventions.

Not all methods require an object; some are class methods, which means that we can call them ‘on the class’ or on an object of the same type. An example would be int.[from_bytes()]p-tp-int-frombyte, which we can specify like this:

     int . from_bytes(…)

$> (123).from_bytes(b'\x02\x10', byteorder='big')  #→528
$> int.from_bytes(b'\x02\x10', byteorder='big')    #→528

The int.[from_bytes(…)]p-tp-int-frombyte method requires arguments.

Attributes

Members that are not methods, are called attributes. Think of attributes as rooms in a house. Given two houses built from the same plan: they will have the same number of rooms (attributes), but they may not have the same content (e.g., furniture).

So, two objects with the same type, will have the same attributes, as defined by their class, but each instance of the common attributes, may have different values. Unless a class prevents it explicitly, we can add instance attributes to any object, at any time:

$> class C: pass            #← user-defined type called `C`.
$> cobj = C()               #← create object and assign `cobj` name.
$> cobj.name = "C Object"   #← create instance attribute `name`.
$> cobj.value = 123.456     #← create instance attribute `value`.

Do not worry too much about the detail above… we just want you at this stage, to get ‘a feel’ for the terminology, and in this case: attributes.

Member Listing

We can use the following function to display the (important) members of any object. It will indicate whether the member is an attribute, or method. It uses the callable and getattr built-in functions.

#### pyList attributes function

def members (obj):
   for m in dir(obj):
      if m.startswith('__'): continue
      attr = getattr(obj, m)
      if callable(attr):
         print(f"method   : {m}")
      else:
         print(f"attribute: {m}")

If you were to run the above function with: members(int), you would get:

method   : as_integer_ratio
method   : bit_count
method   : bit_length
method   : conjugate
attribute: denominator
method   : from_bytes
attribute: imag
attribute: numerator
attribute: real
method   : to_bytes

And, you can of course simply run help(int) or dir(int) in a REPL for all the necessary information about all the members. The members() function can be enhanced to also determine whether a member is an instance member, or a class member, but we shall leave that for later.

Object Type

The most basic, yet important type in Python, is object. It is significant, because it is the ‘master plan’ from which all other ‘plans’ are derived. Practically, this means that all the characteristics of the object class, will be available in all other types.

All the methods and attributes defined in the object class, will be present in all other objects, regardless of their type. We say object is the ‘base class’ for all other classes.

String Conversion

The most important ability all objects of all types inherits from object, is the conversion to string (str). This means you can pass any object to str, or for that matter: repr, and you will obtain a string representation of the object.

>> str(123)        #→ 123
>> str(1.23)       #→ 1.23
>> str(str)        #→ <class 'str'>
>> str(type)       #→ <class 'type'>

The repr will show the output the way you would normally represent the value in Python syntax.

Type Type

To confuse the issue of types a little more, Python has a type called type, which can be used to determine the type of any object passed as argument. When the result is converted to a string (automatically or explicitly), you will get the name of the type.

>> type(type)                    #→ type
>> type(int)                     #→ type
>> type(str)                     #→ type
>> type(0)                       #→ int
>> type(0.0)                     #→ float
>> type(True)                    #→ bool
>> type("")                      #→ str
>> type('')                      #→ str

Note that the CPython REPL will output class ‹type›, while IPython will output just ‹type›. And, if you want to output the result in a script, you have to use print.

Whenever you are in doubt regarding the type of an expression, do:

     print( type( expr ) )

The extra spaces have no effect… we just added them for readability.

Truth

Unlike human societies (and AI to some extend), computer languages have no ‘grey areas’ or ‘false news’ — it's all zeros and ones, which we abstract with Python as False or True keywords respectively. Values that represent ‘truth’ have type bool (boolean), and can only be only one of these two values.

Truth Conversion

The bool (boolean) type in Python, like all types, is a function. It can be used to create boolean values. If called without an argument, it will create the boolean value False.

Absolutely any value of any type, can be converted to boolean. This conversion is based on rules. Almost any value converted to bool, will result in True except for the following:

>> bool()                                  #→ False
>> bool(0)   ; bool(0.0) ; bool(0j)        #→all `False`.
>> bool('')  ; bool("")  ; bool(())        #→all `False`.
>> bool([])  ; bool({})  ; bool(set())     #→all `False`.

Implicit Truths

There are parts of Python syntax that require boolean values (expressions) as part of the syntax. Some operators, like the logical operators, also require operands of type bool.

If the type of an expression is not bool wherever Python expects it, the interpreter will automatically or implicitly, call the bool function to convert the expression to boolean.

This is one very fundamental truth in Python: everything is implicitly convertible to boolean.

Initially, it seems to make no sense that bool("ABC") or bool(123) to have the value True, and bool(0) to result in False. Practical uses of this inescapable truth, will become more apparent later as we explore more Python syntax.

Arithmetic Types

It should be no surprise that Python provides good support for arithmetic of several kinds. It even implements arbitrary-precisions arithmetic on integers.

Integer Type

Python provides the int type to represents integer values. Integers are whole numbers without a fractional part, that are useful in situations where floating point would be overkill. Operations on integers are generally faster than floating point operations.

Since all types in Python are classes, this means that an int value is an object. In turn, an int object will have methods, and attributes. Some methods take arguments, which are sometimes optional:

     obj.method( [ arg… ] )

An example would be the bit_count method, which is an instance method, which means we first need an int object. We can document the syntax as:

     int.[bit_count()]p-tp-int-bit_count

On the other hand, the from_bytes method is a class method, which means we do not (necessarily) need an int object in order to call it. Syntax-wise, we show it as:

     int.[from_bytes(…)]p-tp-int-from_bytes

The int function accepts an optional argument, or one argument, or two arguments. It can be used to truncate float values and return only the integer part. But, it can be passed a string type argument, which will be ‘converted’ to an int… as long as the characters in the string ‘looks like an integer’.

     int()
     int( arg )
     int( arg, base=base)

Note that "123" has type string, and 123 has type int, which has an effect on an operator like __*__ (asterisk), which can have different behaviour depending on the types of the operands:

>> 123 * 2              #→ 246      — int * int ≡ multiplication
>> int("123") * 2       #→ 246      — int * int ≡ multiplication
>> "123" * 2            #→ 123123   — str * int ≡ string repetition
>> 2 * "123"            #→ 123123   — int * str ≡ string repetition

If the string representation of the argument is in base 2 (binary), you must pass a base argument (2). Similar for base 8 (octal), and base 16 (hexadecimal). The literal prefixes are not necessary, but allowed:

>> int("1111011", 2)       #→ 123
>> int("0b1111011", 2)     #→ 123
>> int("1111011", base=2)  #→ 123
>> int("0x7b", 16)         #→ 123
>> int("7B", base=16)      #→ 123

You can pass arguments as a single expression, or by naming the argument, using the name of the parameter as documented — Python call this ‘keyword argument’ syntax. There is a reason for this naming, but is unfortunately not readily apparent from above. Just try to remember that inside a function call operator, something like ‘base=16’, is called a keyword argument.

     func ( parm-name=expr )    ← keyword argument

Floating-Point Type

For situations where integers are not sufficient, as with physical data like distance, mass, velocity, etc., we have the float type. Floating-point types support typical arithmetic operators like multiplication (__*__), addition (+), subtraction (-), and division (/).

Like integers, a float object have methods and attributes, for example:

     float.[hex()]p-tp-float-hex    ← to hexadecimal representation.
     float.[fromhex()]p-tp-float-fromhex    ← from hexadecimal represention.

Try help(float.hex) for example, to see the documentation.

Most of the functions in the standard math module has many function that require floats as arguments, and return results of type float. It also has some mathematical constants like pi (π).

>> import math
>> r = 1.23
>> a = math.pi * r**2        #← A = ¶r²
>> print(f"Area: {a:.4f}")   #→ Area: 4.7529

We shall see a lot more of float later.

Complex Types

If your application requires complex mathematics, Python has got you covered with the built-in complex type. A complex number has real and imaginary parts. The normal arithmetic operators will perform complex arithmetic as expected.

A complex object will have real and imag(inary) attributes.

>> c = complex(3, 4)       #← 3+4i or ‘3+4j’ in Python.
>> c = 3+4j                #← same value, but as literal.
>> print(c)                #→ (3+4j)
>> import math as m
>. m.hypot(c.real, c.imag) #→ 5.0

String Type

Programmer spend a lot of time manipulating strings. It should be no surprise that Python provides the str type to represent string objects. Strings are immutable — once created, the content cannot be modified. This is a safety measure, and also aid efficiency under certain circumstances.

Immutability

A consequence of immutability, is that none of the instance methods of type str will be able to modify the original string — but will return a new copy of the string with possible modifications applied.

>> s = "abcdef"
>> s.upper()                  #← does not change `s`.
>> s = s.upper()              #← that's how to do it.

Encodings

Although Python can support several string encoding, but the internal and default representation make it easy to convert to/from UTF-8. Your Python source files should also be in UTF-8 encoding, as a matter of good convention.

Python also supports byte strings of type bytes, which are not treated as UTF-8, but is useful when converting to/from UTF-8 and some other encoding. Python makes it simple to work with strings — most of the time, it ‘just works’.

>> string = 'Hello, World!'          #← internal representation.
>> encoded = string.encode('utf-8')
>> print(encoded)                    #→ b'Hello, World!'
>> decoded = encoded.decode('utf-8')
>> print(decoded)                    #→ Hello, World!
>> type(encoded)                     #→ <class 'bytes'>

As we mentioned above, any object can be ‘converted’ to a string representation by passing it to the str function.

Regular Expressions

The str class defines many string-manipulation functions. Strings are also often used with the methods and classes of the Standard Library's re module, which implement regular expression pattern matching. There is also the third party regex module with even more regular expression support.

Two major re methods are match() which matches a pattern at the beginning of a string, and search() tries to match anywhere in the string.

>> import re
>> print(re.match("ABC", "ABCDEFG"))
#→ <re.Match object; span=(0, 3), match='ABC'>
>> print(re.match("DEF", "ABCDEFG"))
#→ None 
>> print(re.search("ABC", "ABCDEFG"))
#→ <re.Match object; span=(0, 3), match='ABC'>
>> print(re.search("DEF", "ABCDEFG"))
#→ <re.Match object; span=(3, 6), match='DEF'> 

The str methods split() and replace() can also use regular expression for very flexible string splitting base on complex delimiters, and sophisticated search-and-replace operations.

String Formatting

The str.format allows us to format strings in a multitude of ways. It is newer and more flexible than the older ‘printf-style’ formatting familiar to C programmers which overloads the % (modulus) operator to perform the formatting. From Python 3.6, a much better option is available in the form of formatted string literals, or just f-strings for short.

Printf-Style

The % overloaded operator is inspired by the C printf function. A ‘format string’ contains ‘placeholders’ starting with the percentage sign. Following the %, are format specifiers. The placeholder is replaced with the formatted string representation of an expression.

    "%specifier"   %   expr

>> name = "ABC"
>> age = 123
>> result = "Name: %s (%dy)" % (name, age)
>> print(result)
#→ Name: ABC (123y)
>> print("Name: %s (%dy)" % (name, age))
#→ Name: ABC (123y)

Format Method

The str.[format]p-tp-str-fmt method also has placeholders which are replaced with a formatted string representation of some expression. The placeholders are in the form of matching curly braces: {}. To actually produce curly braces, they must be doubled up: {{ and/or }}.

    "…{}…".format( expr )

>> name = "ABC"
>> age = 123
>> result = "Name: {} ({}y)".format(name, age)
>> print(result)
#→ Name: ABC (123y)
>> print("Name: {} ({}y)".format(name, age))
#→ Name: ABC (123y)

Format Literals

The Python 3.6 formatted string literals allows for a more compact syntax compared to the format method above. It is less error-prone and highly recommended. The big difference is that strings must start with an f prefix, and that inside the curly braces, any expression can appear — this is called string interpolation in many languages.

>> name = "ABC"
>> age = 123
>> result = f"Name: {name} ({age}y)"
>> print(result)
#→ Name: ABC (123y)
>> print(f"Name: {name} ({age}y)")
#→ Name: ABC (123y)

Copyright © 2026 Codi Matters