Python is a late-binding dynamic language. While Python programmers and the Python documentation frequently use the terms "variable" and "assignment" the more precise terms are "name" and "binding."
In your example
x is a name of an object. At each iteration over the loop it's bound to the next object from your list. Python lists, and most other Python containers as well as many other Python object classes, feature iteration functions. That is to say that they define functions following a protocol which allows them to be used in
As you've noted a Python name (analogous to a "variable" in other languages) can be bound to any object of any type. A list can contain any mixture of object references. Thus, when you iterate over a list your "variable" (or loop name(s)) can be bound to objects of different types, potentially different types on each pass through the loop.
You can also have multiple names bound through "tuple unpacking" at each step through the iteration. For example the following snippet of code is a commonly used way to deal with dictionaries:
for key, value in some_dictionary.items():
# do something with each key and its associated value
This form isn't specific to dictionaries. The
.items() method of dictionaries returns a sequence of two item tuples and this form of
for loop could be used with any list or sequence which returned two-item tuples (or even two-time lists). Similarly you could see tuple unpacking used on sequence consisting of items which contain a uniform number of items:
for category, item, quantity, price in some_invoice_query():
# do something with these items, etc.
Conceptually a "variable" in most programming languages is a placeholder for data of a certain type (as well as a name by which that placeholder is referred throughout a program's source code). However, in Python (and other late-binding dynamic languages) a name is a reference to an object and conveys no constraint regarding the type or class of object to which the reference is made.
You can, rather crudely, think of Python names as if they were all void pointers in C.