[Tutor] Pythonic Style Question

Martin A. Brown martin at linux-ip.net
Wed Jun 10 23:07:29 EDT 2020


Hello there,

>Long time programmer (started with punch cards) but fairly new to 
>Python.

As a kid, I played with the detritus that held leftover programs 
.... on punch cards.

Both parents wrote in COBOL.  (Imagine what data security 
professionals of today would say about some kid playing with the 
residual fragments of intellectual property.)

>Decided to try running pylint on it to see what sort or 'Preferred 
>Style' it would lead me to (might as well have something look over 
>the code and critique it) (I know the weaknesses of Linters, but 
>worth a shot)
>
>Getting a lot of coding style errors for module global variables 
>that seem to be a reasonable way to do it, but figured I would ask 
>to see if there is a more Pythonic method to do these.

Quite possibly!  But, see below for more commentary on interpreting 
what you are seeing.

>Example, application will have a number of settings stored in a 
>configuration file, so I have a myconfig.py module that is called 
>with the path to the config file, that uses configparser to read in 
>the options and create a module global variable (config) that other 
>parts of the system can import, and then query/set by accessing.

If you show the code (or small sections), we may be able to help you 
find ways to avoid the warnings from globals.  This is, of course, a 
stylistic choice that pylint is complaining about.  Usually, it's 
possible to read the configuration data in myconfig.py and then use 
an import to put the name into the namespace of another problem 
(without making it global), and then pass it into any objects or 
functions which may need the configurables that came from that 
original configuration file.

Mostly, the solution to that problem is around how to use variable 
scope.  I'd imagine that any language you've come from probably had 
definitions of variable scope, so that's probably not a new idea.  
Here's the place in the Python docs to read about that:

  https://docs.python.org/3/reference/executionmodel.html#resolution-of-names

Of course, it's not forbidden to use globally scoped variables, it's 
generally discouraged since many future sins (or bugs) can be 
avoided by considering scope at first-writing.  I believe this would 
fall into the category of a "code smell" according to pylint, which 
is why it objects and complains.

>pylint first complains that these 'constants' should be in ALL_CAPS 
>(but they aren't constants, so I don't think they should be 
>ALL_CAPS), and in the function that will set it up, complains of 
>the global statement so it can access the module global. I could 
>also create my own access wrappers to get/set options, that other 
>modules will call, but I would think I would still need the module 
>global (and making it _config to mark it as a non-global still gets 
>all the warnings about the constant not being ALL_CAPS).

You are right about there being no 'constants' in Python (though 
there are some third-party libraries that try to fake that).

If you don't actually need to emulate constants or provide get/set 
style methods, I'd say don't bother (there's a human's opinion as 
opposed to pylint's expression of some other humans' opinions).  
I.e. if you won't be offering it as a module or library to others, 
then, why bother with the overhead of getters and setters?

>Is there another better way to do this sort of thing? or is pylint 
>just being over picky (as lints are prone to be) and I need to

Whether the perfect critic, picky or overly picky is entirely up to 
you.  I can tell you that when I run it on some of my sample code 
written to demonstrate the language I get fantastic scores.  When I 
run it against some (reasonably well-tested) production code (which 
lacks the message control exemption comments), I don't get 
particularly good scores.  Why?

  * Because some code has runtime characteristics that pylint cannot 
    predict, so views with skepticism.
  * Because for temporary variables, I actually like one-letter 
    characters. (o for object, d for dict, l for list, s for string)
  * Because (perhaps shame on me) not all of my functions have 
    docstrings.

And, some other such problems.  I'm OK with not getting a 
particularly high score from pylint because I know why I have made 
most of those decisions (or the law of diminishing returns for 
effort have kicked in).

The pylint manual introduction is reasonably self-aware about this, 
too, which is nice.  It's a good tool (and actually, running it just 
now on some production code, I see some things that I might go back 
and revisit):

  https://pylint.readthedocs.io/en/latest/intro.html

> .. put a comment on the statement to tell pylint it is ok?

Yes, you certainly can:

  https://pylint.readthedocs.io/en/latest/user_guide/message-control.html

You can try it out by running:

  pylint -d line-too-long,invalid-name ./path/to/your/proggie.py

I haven't tried "# pylint: disable=line-too-long,invalid-name"

because I kind of like seeing the grousing, in the cases that I run 
pylint.  On the other hand, I do have some minimal expectations.  
While I rarely use pylint, but I hew (generally) to pyflakes and 
pep8, so I run the following as a part of continuous integration / 
or VCS hooks:

  flake8 --ignore E501

And, I ignore that one because, as a verbose lout, I sometimes end 
up with lines longer than 80 characters.

-Martin

-- 
Martin A. Brown
http://linux-ip.net/


More information about the Tutor mailing list