@Ch3steR solved the problem in a comment and this answer just provides some context to the already excellent answer.
The Problem
map(np.ravel, X)
gives a generator object rather than a sequence object like a list or tuple. The difference is not trivial, and some functions which used to accept generators may remove that functionality in the future. That is what happened here.
The Solution(s)
We can unpack everything the generator object will produce, then put that into a list. There are several ways of doing this.
Iterable Unpacking
This is the most concise way to do it since PEP 448. It takes an iterable object such as a generator and unpacks it into a sequence. You're using the list as an argument of np.vstack
so this does need the square brackets, but you could omit them in some cases.
[*map(np.ravel, X)]
Pretty simple, but there are other ways which may make the code clearer to other (or newer) programmers, such as...
List Comprehension
List comprehension has been around for a while and is a clever notation which iterates something with a for loop and puts the result in a list.
[np.ravel(i) for i in X]
This iterates the generator until it has no more objects by using notation which might seem a bit clearer than the iterable unpacking notation above. The for ... in
notation should be familiar to most, if not all, programmers and the square brackets clue you off that this will be in a list.
There is another way which might be clearer still...
List Constructor
This method might be the way that shows the clearest intentions. You have a generator that you want to convert to a list, and you can construct a list from it.
list(map(np.ravel, X))
This works because you are passing an iterable object as the only argument of the list constructor. The constructor will unpack that generator and return a list.