Python provides a rich set of built-in data types that enable you to work with different kinds of data in your programs.

The core numeric types are integers, floats, and complex numbers. Integers represent whole numbers, which are useful for exact counts and computations.

Floats represent real numbers with decimal precision, which is important for scientific and statistical calculations. Complex numbers extend numbers to the complex plane and are used in many scientific domains.

Python has many built-in data types that enable you to store and manipulate data in powerful ways. Choosing the appropriate data type for your use case is important for writing optimized Python code.

This comprehensive guide will explore the various Python data types with code examples.

**Numeric Types**

Numeric data types in Python allow you to work with numeric data like integers, floats, and complex numbers. Let’s look at each of the numeric types in detail:

**Integer (int)**

Integers are whole numbers like -2, -1, 0, 1, 2, 3 etc. They can be positive, negative or 0. Integers are immutable in Python. Some examples:

```
x = 10 Â Â # positive integer
y = -5 Â Â # negative integerÂ
print(type(x)) # <class 'int'>
```

We can perform mathematical operations on integers like addition, subtraction, multiplication etc.

```
a = 12
b = 4
print(a + b) # 16Â
print(a - b) # 8
print(a * b) # 48
```

Integers can be converted to other data types like float, complex etc.

```
num = 10
print(type(num)) # <class 'int'>Â
num2 = float(num)
print(type(num2)) # <class 'float'>
```

**Floating-Point (float)**

Floats represent real numbers like -1.5, -0.4, 0.0, 1.25, 9.8 etc. They contain a decimal point. Useful for computations where precision is required. Some examples:

```
a = 1.5 Â Â
b = -0.4
print(type(a)) # <class 'float'>
```

Floats support math operations like addition, subtraction etc.

```
x = 3.0
y = 5.5Â
print(x + y) # 8.5
print(x - y) # -2.5Â
print(x * y) # 16.5
```

They can be converted to other types like int, complex etc.

```
a = 1.2
print(type(a)) # <class 'float'>
b = int(a)Â
print(type(b)) # <class 'int'>
```

**Complex**

Complex numbers are written as x + yj, where x is the real part, and y is the imaginary part. They are useful for scientific and mathematical applications.

```
x = 5 + 3j
print(type(x)) # <class 'complex'>
```

We can perform operations like addition and multiplication on complex numbers.

```
a = 2+3j
b = 5+4j
print(a + b) # 7+7jÂ
print(a * b) # -7+26j
```

They can be converted to other types like int, float etc.

```
x = 5 + 3j
print(type(x)) # <class 'complex'>
y = float(x)
print(type(y)) # <class 'float'>
```

**Boolean Type**

Boolean represents logical values True and False. Useful for conditional testing and logic. For example:

```
x = True
y = False
print(type(x)) # <class 'bool'>
```

Boolean operators like and, or, not can be used to compose logical expressions and conditions.

```
a = True
b = False
print(a and b) # FalseÂ
print(a or b) # True
print(not a) # False
```

Other data types can be converted to booleans based on their truth value.

```
x = 5
print(bool(x)) # TrueÂ
y = 0
print(bool(y)) # False
```

**Sequence Types**

Sequence types allow storing collections of data in an ordered way. Let’s go through them one by one:

**String (str)**

Strings represent sequences of unicode characters like letters, digits, spaces etc. They are immutable in Python. Some examples of creating strings:

```
s1 = 'Hello'
s2 = "World"
print(type(s1)) # <class 'str'>
```

We can access individual characters using indexing:

```
s = 'python'
print(s[0]) # p
print(s[3]) # h
```

Strings support operations like concatenation, slicing, length etc.

```
s1 = 'Hello'
s2 = 'World'
print(s1 + ' ' + s2) # Hello World
print(len(s1)) # 5
```

Format specifiers like %s can be used for formatting:

```
name = 'John'
print('My name is %s' % name) # My name is John
```

**List**

Lists are ordered collections of values that are mutable (modifiable). Allows for storing different data types.

```
nums = [1, 2, 3]Â
fruits = ['apple', 'mango', 'banana']
print(type(nums)) # <class 'list'>
```

We can access elements using index. Lists are mutable.

```
nums[0] = 5Â
print(nums) # [5, 2, 3]
```

Lists support operations like concatenation, slicing, length etc.

```
fruits = ['apple', 'banana', 'mango']
print(len(fruits)) # 3
print(fruits[1:]) # ['banana', 'mango']
```

**Tuple**

Tuples are ordered collections of values that are immutable (cannot be modified). Allows storing different data types.

```
point = (2, 3) # parenthesis not required but recommended
colors = ('red', 'blue', 'green')
print(type(point)) # <class 'tuple'>
```

We can access elements using an index but cannot modify tuples.

`point[0] = 5 #ERROR: cannot modify tuple`

Tuples support operations like concatenation, slicing, length etc.

```
colors = ('red', 'blue', 'green') Â
print(len(colors)) # 3
print(colors[1:]) # ('blue', 'green')
```

**Range**

A range represents an immutable sequence of numbers. It is commonly used to loop over sequences of numbers.

```
nums = range(5) # 0 to 4Â
print(list(nums)) # [0, 1, 2, 3, 4]
```

Ranges are often used in for loops:

```
for i in range(3):
Â Â print(i)
# Output:
# 0
# 1 Â
# 2
```

We can also create ranges with a start, stop, and step size.

```
nums = range(3, 8, 2)Â
print(list(nums)) # [3, 5, 7]
```

**Set Types**

Sets are unordered collections of unique values. They support operations like membership testing, set math etc.

**Set**

Sets contain unique values only. Elements can be added and removed.

```
colors = {'red', 'blue', 'green'}
print(type(colors)) # <class 'set'>
```

Set elements can be tested for membership and added/removed. Sets are mutable.

```
'red' in colors # True
colors.add('yellow')
colors.remove('blue')
```

Set math operations like union intersection work between sets.

```
set1 = {1, 2, 3}
set2 = {3, 4, 5}
print(set1 | set2) # {1, 2, 3, 4, 5}
print(set1 & set2) # {3}
```

**Frozenset**

Frozenset is an immutable variant of a Python set. Elements cannot be added or removed.

```
colors = frozenset(['red', 'blue', 'green'])
print(type(colors)) # <class 'frozenset'>Â
colors.add('yellow') # AttributeError
```

frozensets can be used as dictionary keys and in set operations.

**Mapping Type**

Mapping types allow storing data as key-value pairs. Dictionaries are the main mapping type in Python.

**Dictionary**

Dictionaries consist of key-value pairs and are enclosed in curly braces {}. Useful for storing related data.

```
student = {
Â 'name': 'John',
Â 'age': 20,Â
Â 'courses': ['Math', 'Science']
}
print(type(student)) # <class 'dict'>
```

Dictionary elements can be accessed via keys and modified. Dictionaries are mutable.

```
student['name'] = 'Mark' # update value
print(student['courses']) # ['Math', 'Science']
```

Common dict operations include length, adding/removing keys, iteration etc.

```
print(len(student)) # 3Â
student['email'] = 'john@example.com' # add key-value
for key in student:
Â Â print(key, student[key]) # print each item
```

**Binary Types**

Binary types in Python are used when working with binary data like bytes, byte arrays, etc.

**Bytes**

Bytes represent immutable sequences of bytes. Example:

```
data = b'hello'Â
print(type(data)) # <class 'bytes'>
```

Bytes support operations like indexing, length, concatenation, etc., but are immutable.

```
print(data[0]) # 104
print(len(data)) # 5
data2 = data + b'world' # cannot modify, only concatenate
```

**Bytearray**

Bytearray represents mutable sequences of bytes. They can be modified in place.

```
data = bytearray(b'hello')
print(type(data)) # <class 'bytearray'> Â
data[0] = 106 # mutable
```

Bytearray supports typical sequence operations like indexing, concatenation etc.

```
print(data[0]) # 106Â
data2 = data + bytearray(b'world')
```

**Memoryview**

Memoryview objects allow accessing the internal data of objects that support the buffer protocol directly without copying. Useful for advanced optimizations.

```
data = memoryview(b'hello')
print(data[0]) # 104
```

Memoryview supports slicing and editing without copying the buffer. Advanced usage for performance.

```
data[1:4] = b'i' # edit in place
print(data) # b'hiello'
```

**None Type**

The None type represents the absence of a value. It is similar to null in other languages.

```
x = NoneÂ
print(type(x)) # <class 'NoneType'>
```

None is commonly used as a placeholder for optional or missing values.

```
def print_if_not_none(x):
Â Â if x is None:
Â Â Â Â print('x is None')
Â Â else:
Â Â Â Â print(x)
```

The operator can check if something is None.

```
x = None
print(x is None) # True
```

So, in summary, Python comes equipped with a diverse set of built-in data types – numeric, textual, collections, mappings, and more.

Choosing the appropriate data type leads to efficient memory usage and better performance. Manipulating data types form an integral part of Python programming.

I hope this overview gave you a good understanding of the different data types available in Python, along with plenty of code examples demonstrating their usage.

If you find this post exciting, find more exciting posts onÂ Learnhub Blog; we write everything tech fromÂ Cloud computingÂ toÂ Frontend Dev,Â Cybersecurity,Â AI, andÂ Blockchain.