Opinion on best practice...

Steven D'Aprano steve+comp.lang.python at pearwood.info
Wed Feb 6 18:46:17 EST 2013


Dennis Lee Bieber wrote:

> On Wed, 6 Feb 2013 17:16:04 +1100, Chris Angelico <rosuav at gmail.com>
> declaimed the following in gmane.comp.python.general:
> 
>> 
>> It feels silly enough translating this OS/2 batch script:
>> 
>> @logon SOME_USER /pSOME_PASS /vl
>> @e:\rexx\load
>> @db2 start database manager
>> @exit
>> 
>> into this REXX script:
>> 
>> /* */
>> "@logon SOME_USER /pSOME_PASS /vl"
>> "@e:\rexx\load"
>> "@db2 start database manager"
>> "@exit"
>> 
>> And that's a change I've made myriad times (to \startup.cmd on many an
>> OS/2 boot drive) It's far far worse translating it into Python, Pike,
>> or any other "good language".
>>
> Though that is the nice feature of REXX*... Anything that wasn't
> parsable as a REXX statement was automatically sent to the current
> command processor.

Nice? Are you being sarcastic? What you're describing sounds like a
classic "Do What I Mean" system, which invariably end up being followed by
anguished shouts of "Noooo, I didn't mean that!!!".

The Zen of Python is not just design principles for *Python*. They hold for
other languages as well. Having to explicitly send a command to an external
command processor (say, the shell) is much better **and safer** than
implicitly doing so on SyntaxError, even if such a requirement makes your
program more verbose.


> Converting such to Python turns into a mishmash of (pick your
> favorite) os.system(), subprocess.Popen(), etc. with their particulars
> of how to pass command line arguments.

Why on earth would anyone use a "mismash" within the one script? Pick one
and stick to it. If you have only wish to give a few commands, and don't
care about getting data back from them, use os.system which is
embarrassingly easy and almost as concise as the REXX script above:

from os import system as s
s("@logon SOME_USER /pSOME_PASS /vl")
s("@e:\rexx\load")
s("@db2 start database manager")
s("@exit")


If you find yourself needing complicated string escapes, use subprocess.call
instead.

If you do care about getting data back from the external system, then you
need to integrate the external code with your Python (or REXX) code, and
that requires more than just firing off a few system commands and
forgetting about them. That's inherently complicated, because there are
many possible factors to care about:

- do you care about stdout, stderr, stdin?
- start a new subshell?
- deal with shell metacharacters?
- deadlocks?

etc. Lack of terse syntax is the least of your worries here, doing these
things *correctly* is hard in the shell. Having to type a few extra symbols
doesn't make it any harder in any meaningful way, and readable syntax can
actually make it simpler to reason about the code.


If you say "Anything that isn't parsable is automatically sent to the
shell", it doesn't sound too bad. But when you say "Unparseable junk is
implicitly treated as code and sent off to be executed by something which
traditionally tends to be forgiving of syntax errors and has the ability to
turn your file system into so much garbage", it sounds a tad less
appealing.



-- 
Steven




More information about the Python-list mailing list