You could look at the last dimension's size instead with -1:
>>> x3.shape[-1]
6
>>> x4.shape[-1]
3
However, to get the broadcasted shape for 2D and 1D arrays alike, you might want to unpack the shape and use 1 as the default number of rows:
>>> *r, c = x3.shape
>>> ((r or [1])[0], c)
(1, 6)
>>> *r, c = x4.shape
>>> ((r or [1])[0], c)
(2, 3)
Which means:
if the array is 1D, r is an empty list [], which is falsy, so you end up with (r or [1])[0] equal to [1][0], i.e. 1.
if the array is 2D, r is a list containing the number of rows as its first element, a non-empty list is truthy, so you end up with r[0].
See extending iterable unpacking for more on this usage of the asterisk * in Python.
An alternative way is to prepend 1 to the shape straight away. Then, extract the last two elements of that tuple. This will return the correct row and column numbers, regardless if it's a 1D- or 2D-array:
>>> ((1,) + x3.shape)[-2:]
(1, 6)
>>> ((1,) + x4.shape)[-2:]
(2, 3)