Well, it depends on what you mean with "programmatically".
If you just need automatic connections and you run jack, you can use jack-plumbing.
You could also use aplaymidi/arecordmidi outputs and then use aconnect, as pointed out by Clemens.
If, otherwise, you need much more control, you'll need to interface with the pyalsa's alsaseq python module, possibly using an event loop (I used to interface with a Qt's QThread).
Unfortunally, pyalsa doesn't support python 3 yet (and I really hope they'll fix it).
You have to create an input "monitor" port, and connect it to the alsaseq system client and its system announce port, which notifies of every change in the alsa MIDI graph.
Then, within the thread you use to monitor the graph changes, you can connect ports if their names/properties suit your needs.
Remember that alsaseq creates an event for every client created (alsaseq.SEQ_EVENT_CLIENT_START) and then an event for each port created (alsaseq.SEQ_EVENT_PORT_START). Also, when a client is "killed", usually you will receive a port exit for each port (alsaseq.SEQ_EVENT_PORT_EXIT) and, finally, a client exit (alsaseq.SEQ_EVENT_CLIENT_EXIT).
You will be probably interested in newly created port events, which have a python dict containing addr.client:client_id and addr.port:port_id items.
You can access client names using alsaseq.Sequencer().get_client_info(client_id) and port names with alsaseq.Sequencer().get_port_info(port_id, client_id) (be careful about the order of parameters): they will return dictionaries containing different values, but both of them will have a "name" key (AFAIR, the ID is not implicit for ports, which means that you might find that a client has 2 ports, and the second port's id is 2 because the port_id 1 has been destroyed).
Finally, the connections are made using alsaseq.Sequencer().connect_ports((client_id, port_id), (client_id, port_id)).
I know that this isn't the easiest method to get things done (pyalsa support and documentation are not very clear nor simple), but, as far as I've seen, it's the better and less error-prone I've found yet for this kind of needs...
Best regards,
Maurizio