TL;DR;
import streamlit as st
st.markdown("----", unsafe_allow_html=True)
columns = st.columns((2, 1, 2))
button_pressed = columns[1].button('Click Me!')
st.markdown("----", unsafe_allow_html=True)
You will get the following result (if default: narrow streamlit page settings):

Streamlit columns
Streamlit docs defines columns() in the following way:
columns = st.columns(spec)
where specs are either int or a list (or a tuple). For example, st.columns([3, 1, 2]) creates 3 columns where the first column is 3 times the width of the second, and the last column is 2 times that width. Hence, you may play around with their relative width.
What is more useful, you will get a list of columns, so you may address them as consequent numbers. You may use that in case of flexible numbers of columns:
import streamlit as st
import random
column_qty = random.randint(1, 10) # random number of columns on each run
buttons_pressed = [] # here we will collect widgets
st.markdown("----", unsafe_allow_html=True)
# create all columns with arbitrary relative widths
columns = st.columns([random.randint(1, 3) for _ in range(column_qty)])
# Show widgets in them
for x, col in enumerate(columns):
# if you need a static widget, just use: `col.text("some text")`
buttons_pressed.append(col.checkbox(f'{x}')) # add widgets to the list
st.markdown("----", unsafe_allow_html=True)
st.text(f'Total columns: {column_qty}')
# Check each widget for its state
for x, btn in enumerate(buttons_pressed):
if btn:
st.write(f"{x}") # NOTE: some columns may be dropped next run!

A very useful thing for flex input forms.