I have a simple task I want to perform over ssh: return all files from a given file list that do not exist.
The way I would go about doing this would be to wrap the following in an ssh session:
for f in $(files); do stat $f > /dev/null ;done
The stdout redirect will ignore all good files and then reading the stderr will give me a list of all non found files.
I first thought of using this bash code with the ssh part inside a subprocess.run(..., shell=True) but was discouraged to do so. Instead,paramikowas suggested. 
I try to understand why and when native python is better than subprocessing bash

Computability with different OS (not an issue for me as the code is pretty tightly tied to Ubuntu)
Error and exception handling - this one I do get and think it's important, though catching an exception or exit code from subprocess is kinda easy too

The con in my eyes with native python is the need to involve somewhat complicated modules such as paramiko when bash's ssh and stat seem to me as more plain and easy to use
Are there any guidelines for when and how to choose bash over python?
This question is mainly about using a command over ssh, but is relevant for any other command that bash is doing in a short and easy way and python wraps
There are really three choices here: doing something in-process (like paramiko), running ssh directly (with subprocess), and running ssh with the shell (also with subprocess).  As a general rule, avoid running the shell programmatically (as opposed to, say, upon interactive user request).
The reason is that it’s a human-oriented interface (thus the easy separation of words with spaces and shortcuts for $HOME and globbing) that is vastly underpowered as an API.  Consider, for example, how your code would detect that ssh was missing: the situation doesn’t arise with paramiko (so long as it is installed), is obvious with subprocess, and is just an (ambiguous) exit code and stderr message from the shell.  Also consider how you supply the command to run: it already must be a command suitable for the shell (due to limitations in the SSH protocol), but if you invoke ssh with the shell it must be encoded (sometimes called “doubly escaped”) so as to have the local shell’s interpretation be the desired multi-word command for the remote shell.
So far, paramiko and subprocess are pretty much equivalent.  As a more difficult case, consider how a key verification failure would manifest: paramiko would describe the failure as data, whereas the others would attempt to interact with the user (which might or might not be present).  paramiko also supports opening multiple channels over one authenticated connection; ssh does so as well but only via a complicated ControlMaster configuration involving Unix socket files (which might not have any good place to exist in some deployments).  Speaking of configuration, you may need to pass -F to avoid complications from the user’s .ssh/config if it is not designed with this automated use case in mind.
In summary, libraries are designed for use cases like yours, and so it should be no surprise that they work better, especially for edge cases, than assembling your own interface from human-oriented commands (although it is very useful that such manual compositions are possible!).  If installing a non-standard dependency like paramiko is a burden, at least use subprocess directly; cutting out the second shell is already a great improvement.
File related operations python subprocess vs. native python