There is no "one size fits all" answer. What makes sense on your system doesn't make sense for other systems. (Python should trivially support only a single encoding if this wasn't the case, don't you think?)
On any computer, the main consideration is to remain compatible with other utilities on the system. If your system is a "big iron" mainframe from the dark ages, probably everything needs to be configured to use some horrible legacy 8-bit encoding (or worse!) At the other end of the spectrum, the world is moving towards Unicode and specifically the UTF-8 encoding (see also https://utf8everywhere.org/); if you are using a reasonably modern non-Windows system, your locale will probably indicate that the system is set up for UTF-8, and then that's what you should use (and what Python is almost certainly already configured to use as its default encoding; so you really just need to say text=True and not explicitly name an encoding).
That leaves Windows, which commonly is configured with whatever code page makes sense for the geography where it was sold; in the Americas and Western Europe, that means code page 1252, while in other parts of the world it means something else (Eastern Europe 1250 or 1251, various other country- or region-specific code pages in various other parts of the world); but again, with subprocess you can get away with just text=True and have Python choose on your behalf.
The keyword argument text=True was previously called universal_newlines=True which still works; really old Python 3 versions will still require you to explicitly encode and decode, and of course there are situations where you need or want to use raw binary encoding to communicate with selected external utilities.
Examples:
r = subprocess.run(['git', 'rev-parse', '--short', 'HEAD'],
text=True, capture_output=True)
print(r.stdout) # implicitly uses Python's default encoding to decode
s = subprocess.run(['dd', 'if=/dev/urandom', 'bs=32', 'count=1'],
capture_output=True)
random_bytes = s.stdout # not text, no encoding, just raw bytes
# Actually don't use Popen when run() can do the job
fugly = subprocess.Popen(['cat', '/etc/motd'], text=True)
stdout, stderr = fugly.communicate()
fugly.wait() # really, use subprocess.run() instead
# If you specifically want a particular encoding, of course, go for it
weird = subprocess.run(['iconv', '-t', 'koi8-u'],
stdin=open('utf8.txt'), encoding='koi8-u', capture_output=True)
(subprocess.run() replaces check_output and friends, though you can of course still use them for convenience. Most of these examples are really tortured anyway, and you should really use Python's native functionality instead of an external subprocess.)
On systems which are in the middle of a migration, you really have to check individually for each utility which encoding it requires, though for UTF-8 it's conveniently transparent, and so many utilities which were never explicitly adapted to UTF-8 will simply continue to work. The problem areas will be collation (sort order) and corner cases like Unicode normalization (a naïve string comparison will not regard the sequence U+006F U+0308 as equivalent to the code point U+00F6 even though they both represent the single glyph ö).
Communication over a network can be troublesome. For HTTP, ISO 8859-1 (aka Latin-1) was codified as the standard character set for HTML for a while, though it is now UTF-8. For many network protocols, it is unspecified, and you just have to experiment. Modern protocols which involve textual information should specify an encoding or a mechanism for explicitly tagging the character set and encoding of any textual data; the MIME headers were originally specified for email, but have made their way to several other protocols, including HTTP. Email has a confusing array of additional encodings to enable complete transparency over a channel which used to only support 7-bit ASCII; notice how message bodies, message headers, and file name attributes in MIME headers each have their own mechanism for this. (RFCs 2045, 2047, and 2231.)