In this example you aren't really 'stitching' together u0 and p0 to form z in the sense that z is not being created (via reference or otherwise) when you use the 'assign' function.
Rather, the 'z' function already exists and is a mixed function over the space (two scalar fields). The assign command is just copying the values of u0 and p0 into that z function. If, after the assign statement, you change u0, the value in z will not change because u0 and the first subspace of z are completely different object which were merely set equal. z.sub(0) doesn't actually link to u0 in any way.
Now if you did something like (untested):
z = Function(Z)
u0, p0 = split(Z)
then u0 is the first subspace of z, so changing it will change z, and vise versa. (note how you don't have to define u0 as a function beforehand).
Note: If you want to then initialize u0, you will need to use the assign command again with something like (untested):
assign(z.sub(0), interpolate(v0,V))
Does that help?