Just in case you're looking for maximum efficiency on larger lists, an alternative to the list comprehension in this case is using map + operator.attrgetter. You can either loop over the map directly:
from operator import attrgetter
for X in map(attrgetter('X'), randomList):
which involves no temporary list (map lazily pulls items on demand in Python 3), or if you really need the list, just wrap in the list constructor or use list unpacking to run it out eagerly:
Xs = list(map(attrgetter('X'), randomList))
# or
Xs = [*map(attrgetter('X'), randomList)]
For small input lists, this will be slower than the list comprehension (it has a slightly higher setup overhead), but for medium to large inputs, it will be faster (the per-item overhead is slightly lower, as it involves no per-item bytecode execution).
To be clear, it's still going to have to loop over the list. There is no magic way to get the attributes of every item in a list without looping over it; you could go to extreme lengths to make views of the list that seamlessly read the attribute from the underlying list, but if you accessed every element of that view it would be equivalent to the loop in work required.
listobject do no support vectorized attribute access, or any vectorized operations. Although in this case (in most cases), you should just loop over the list directly:for item in randomList: item.Xlists worth ofXs, or how to pull theXs efficiently?