33

I am a Python programmer primarily who uses pylint for linting source code. I am able to eliminate all of the warnings except one: Invalid name for a constant. Changing the name to all caps fixes it, but am I really supposed to do that? If I do it, I find that my code looks ugly as most of the variables are constant (according to pylint).

  • 1
    If most of your variables are module-level constants, you're probably doing something unusual. Most of them should live inside functions. – RemcoGerlich Feb 16 '17 at 14:09
  • 1
    can you show us a sample of your code that pylint thinks are constants? – Winston Ewert Feb 16 '17 at 17:26
  • @WinstonEwert NOTES_DIRECTORY = argv[1] chdir(NOTES_DIRECTORY) FILES = glob('*.txt') RAND_FILE = choice(FILES) with open(RAND_FILE) as notes_file: POINTS = notes_file.readlines() RAND_POINT = choice(POINTS) – Abhishek Kumar Feb 20 '17 at 15:53
  • @AbhishekKumar, is your code in a function, or at the top level? – Winston Ewert Feb 20 '17 at 19:25
  • @WinstonEwert At the top level and after following PyLint's instructions. – Abhishek Kumar Feb 21 '17 at 1:19
32

You are probably writing code like this:

notes_director = argv[1]
chdir(notes_director)
files = glob('*.txt')
rand_file = choice(files)
with open(rand_file) as notes_file: 
    points = notes_file.readlines() 
    rand_point = choice(points)

You should move this code into a function:

def main():
    notes_director = argv[1]
    chdir(notes_director)
    files = glob('*.txt')
    rand_file = choice(files)
    with open(rand_file) as notes_file: 
        points = notes_file.readlines() 
        rand_point = choice(points)

# actually call the main function    
main()

Pylint assumes that code that actually does the work will be inside a function. Because you have this code at the top level of your code instead of inside a function it gets confused.

Generally speaking, it is better style to do work inside a function instead of at the top level. This allows you to better organize what you are doing and facilitates reusing it. You should really only have code performing an algorithm outside of a function in a quick and dirty script.

  • 1
    Strongly disagree, I think there are many good Pythonic reasons to use module level variables. I think this advice is merely an artifact of pylint misreading PEP8, and assuming the converse of "constants should be module level" should also be true. – MetricSystem May 21 at 21:58
21

Yes. According to PEP8s rule on constants:

Constants are usually defined on a module level and written in all capital letters with underscores separating words. Examples include MAX_OVERFLOW and TOTAL.

Long Version:

In the Python community (as in many other communities) exist conventions about how to write code. This is different from working code: even if you write your constants all lowercase, your code still works.

But there is community consensus (as documented in PEP8) which is "enforced" with tools like pylint. If you program for your own happiness, you may neglect the hints pylint gives you. If you want open exchange with the community, aka »someone besides myself should use my code«, you should prepare your code according to PEP8.

  • 7
    On the other hand, it's entirely possible for pylint to get it wrong. Python doesn't provide a way of distinguishing a constant from a variable, other than that the constant is expected to always have the same value. pylint assumes that anything that is only set once and doesn't ever change is a constant, but unless it's intended to be a constant, that could just be an artifact of the implementation. And specifically the code given in the comment to the question has values that will be different on each run, therefore should not be considered constants even if pylint thinks they are. – Jules Mar 21 '18 at 8:46
  • @Jules I would call variables set once and changing during runtime never again a constant, hence exists in many languages (e.g. in JS) a const keyword. Although the initial value is different, other than maybe PI. – Thomas Junk Aug 8 '18 at 7:27
  • 1
    I'd distinguish between an immutable variable (i.e. something that's set at runtime and not changed) and a constant (i.e. something that is the same in every program run, and if the language provides the option to do it could be computed at compile time) ... the point is that because there's a lack of any way of specifying the distinction to python, pylint assumes the latter even when the former is the case. – Jules Aug 8 '18 at 8:02
  • Pylint is definitely in the wrong, in that it read "constants should be module level" and assumed the converse "module level should be constants". But because it's otherwise a good, useful tool seems we're getting stuck with it. – MetricSystem May 21 at 21:57
  • @MetricSystem what - in your opinion - function would a module level variable have besides being a constant? Should it be mutable? – Thomas Junk May 22 at 7:53
12

The PEP8 and Python community norm is to use ALL_CAPS_CONSTANTS. It's a common visual clue, used for decades in C, Java, Perl, PHP, Python, bash, and other programming languages and shell environments. But in modern online parlance, ALL CAPS SIGNIFIES SHOUTING. And shouting is rude.

Python is, however, rather inconsistent about ALL_CAPS_CONSTANTS. JavaScript may have Math.PI, but Python has math.pi. There's no more recognizable or enduring constant than π. Or consider sys.version_info, the version of Python you're running on. 100% constant over the life of your program--far more than PORT or MAX_ITERATIONS or other constants you'd define. Or how about sys.maxsize? Your platform's maximum native integer value is constant over not just one or two program runs, but the life of your hardware.

If these constants--including some like π and e that are fundamental constants of the universe, and will not vary over all eternity--if they can be lower-case, well...so can other constants. You can choose.

Remember, PEP8 is a style guide. A guideline, not a law. A guideline often contravened even by Python's standard library. And citing another core Python guideline, PEP20 (aka "The Zen of Python"):

  • Beautiful is better than ugly
  • Readability counts
  • Practicality beats purity.

On a practical note, when a program's YELLY_CONSTANT and SHOUTY_PARAMETER starts to grate, it helps to remember that the all-caps constants generally are not really enduring Platonic ideals, but parameters of a program run. There is nothing truly constant about PORT, SITENAME, or NUMRUNS, and they don't have to be managed as standalone program globals. For example, they can be dropped into a dictionary as a globally-accessible bundle of program parameters:

config = {
    'port': 80,
    'sitename': "Bubba's Blog",
    'numruns': 100,
}

Python also has a fine keyword parameter passing facility that reduces the need to use APPARENTLY_ANGRY_GLOBAL_VARIABLES:

def process_data(sitename, port=80, numruns=100):
    ...

process_data("Bubba's Blog")

In practice, many of these values will be (or should be) read from config files, OS environment variables, command line arguments, or other sources to satisfy the inversion of control principle/pattern. But that's a larger story for another day.

1

Yes, it's quite common in most programming language (at least those I use).

You can refer to this Google link to share a common style between developers of the same team.

It's advised to use

Type                  |Public          |Internal
Global/Class Constants|CAPS_WITH_UNDER |_CAPS_WITH_UNDER

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.