Content from Introduction
Last updated on 2025-10-27 | Edit this page
Estimated time: 15 minutes
Overview
Questions
- Why does consistent code style matter in software development?
- What are some common code styling practices and conventions?
- How can poor coding style lead to bugs and maintenance issues?
- What is a linter, and how does it help improve code quality?
Objectives
- Understand why consistent code style is important for collaboration and long-term maintainability.
- Recognise how maintaining good code style can reduce bugs and improve code quality.
- Identify key code style practices and how they vary between programming languages.
- Explain what a linter is and describe its role in detecting errors and enforcing style.
This session introduces the importance of code style and linting in writing clean, consistent, and maintainable code. You will learn how following a defined style guide improves code readability and collaboration, and how automated tools, known as linters, can help identify and fix style issues early in the development process. We will explore common linting tools and how to integrate them into your software development workflow.
Code Style
Why Does Code Style Matter?
Software development is inherently a collaborative activity. Even if you do not currently intend for anyone else to read your code, chances are someone will need to in the future — and that person might even be you, months or years later. By following and consistently applying code styling guidelines, you can significantly improve the readability and maintainability of your code. Consistency plays a vital role in this process. Adopting a clear set of style guidelines not only helps you write uniform code but also makes it easier to switch between projects. This is especially important when working as part of a team, where shared understanding and clarity are essential.
Key Code Style Practices & Conventions
Styling practices and conventions play a key role in writing readable and maintainable code, but they can vary significantly between programming languages. These conventions generally cover aspects such as line length, line splitting, the use of white space, naming conventions for variables, functions, and classes, as well as indentation and commenting styles (where not enforced by the language itself).
It is important to note that programmers often have strong and differing opinions about what constitutes good style. For example, many style guides recommend a maximum line length of 80 characters, a convention that dates back to older hardware and terminal limitations. While some developers continue to find this helpful for readability and side-by-side editing, others argue that it feels unnecessarily restrictive on modern screens. Despite these differences, adopting and adhering to a consistent style within a project helps ensure clarity and makes collaboration smoother.
There are many established code style guides tailored to specific programming languages, such as:
- PEP8 and Google Style Guide for Python
- Google C++ Style Guide and C++ Core Guidelines for C++
- Airbnb JavaScript Style Guide and Google JavaScript Style Guide and JavaScript Standard Style for JavaScript
- Go Style Guide and Go Styleguide for Go.
Maintaining Code Quality to Reduce Bugs
Poor coding style can lead to bugs and maintenance issues because it makes code harder to read, understand, and debug. Inconsistent naming, unclear structure, and sloppy formatting can cause confusion about what the code is doing, making it easier to introduce mistakes. Many things that seem harmless and do not cause immediate syntax errors while writing code can produce logic errors, wrong results and lead to issues later on - making them especially tricky to detect and fix. Small issues like unused variables, accidental redefinitions, or incorrect scoping can go unnoticed and later cause unexpected behavior or subtle logic errors. Over time, this makes the codebase more fragile, harder to maintain, and much more difficult for others — or even your future self — to fix or extend.
Some examples of small oversights that stack up over time include:
- defining variables or importing modules or headers that that are never used can clutter the code
- using vague variable names like
dataeverywhere can make it unclear whichdatayou are actually handling, causing mistakes - bad indentation can cause logic errors — like running a block of code when you did not intend to
- variable scoping problems (e.g. reusing the same variable name in different scopes can lead to shadowing, where a local variable hides a global or outer-scope variable, resulting in unexpected values being used.
Linters
What is a Linter and Why Use One?
A linter is a tool that performs static analysis on your code — meaning it examines the source code without running it — to detect potential errors, stylistic issues, and code patterns that might cause bugs in the future. The term originates from a 1970s tool for the C programming language called “lint”.
Linters help catch errors early and enforce consistent code style, making your code more reliable, readable, and easier to maintain. They are especially useful for improving code quality and streamlining collaboration in teams.
Practical Work
In the rest of this session, we will walk you through how to use a linting tool.
The use of linting tools is often automated through integration with Continuous Integration (CI) pipelines or pre-commit hooks available in version controlled code repositories, helping to streamline the development process and ensure code quality consistently on each commit. This is covered in a separate session.
Content from Example Code
Last updated on 2025-10-28 | Edit this page
Estimated time: 10 minutes
Overview
Questions
- Why should I write readable code?
- What is a “code smell”?
Objectives
- Obtain and run example code used for this lesson
- List the benefits of writing readable code
- Describe the key indicators of a “bad code smell”
Obtaining Example Code
For this lesson we’ll be using some example code available on GitHub, which we’ll clone onto our machines using the Bash shell. So firstly open a Bash shell (via Git Bash in Windows or Terminal on a Mac). Then, on the command line, navigate to where you’d like the example code to reside, and use Git to clone it. For example, to clone the repository in our home directory, and change our directory to the repository contents:
Examining the Code
Next, let’s take a look at the code, which is in the root directory
of the repository in a file called climate_analysis.py.
PYTHON
import string
shift = 3
comment = '#'
climate_data = open('data/sc_climate_data_10.csv', 'r')
def FahrToCelsius(fahr):
celsius = ((fahr - 32) * (5/9))
return celsius
def FahrToKelvin(fahr):
kelvin = FahrToCelsius(fahr) + 273.15
return kelvin
for line in climate_data:
data = line.split(',')
if data[0][0] != comment:
fahr = float(data[3])
celsius = FahrToCelsius(fahr)
kelvin = FahrToKelvin(fahr)
print('Max temperature in Celsius', celsius, 'Kelvin', kelvin)
The code is designed to process temperature data from a separate data file. The code reads in data line by line from the data file, and prints out fahrenheit temperatures in both celsius and kelvin.
The code expects to find the data file
sc_climate_data_10.csv (formatted in the Comma Separated
Value CSV format) in the data directory, and looks like
this:
# POINT_X,POINT_Y,Min_temp_Jul_F,Max_temp_jul_F,Rainfall_jul_inch
461196.8188,1198890.052,47.77,58.53,0.76
436196.8188,1191890.052,47.93,58.60,0.83
445196.8188,1168890.052,47.93,58.30,0.74
450196.8188,1144890.052,48.97,56.91,0.66
329196.8188,1034890.052,49.26,59.86,0.78
359196.8188,1017890.052,49.39,58.95,0.70
338196.8188,1011890.052,49.28,58.73,0.74
321196.8188,981890.0521,48.20,61.41,0.72
296196.8188,974890.0521,48.07,61.27,0.78
299196.8188,972890.0521,48.07,61.41,0.78
It contains a number of lines, each containing a number of values, each separated by a comma. There’s also a comment line at the top, to tell us what each column represents.
Now let’s take a look at the Python code, using any text or code
editor you like to open the file. You can also use nano if
you’d prefer to use the command line, e.g.
The code opens the data file, and also defines some functions to do two temperature conversions from Fahrenheit to Celsius and Fahrenheit to Kelvin. Note that for the purposes of this lesson, the code is deliberately written to contain some issues!
Why Write Readable Code?
Readable Code
As a group, answer the following questions:
- Who has seen or used code that looks like this?
- Who has written code like this?
No one writes great code that’s readable, well formatted, and well designed all the time. Sometimes you often need to explore ideas with code to understand how the code should be designed, and this typically involves trying things out first. But… the key is that once you understand how to do something, it’s a good idea to make sure it’s readable and understandable by other people, which may include a future version of yourself, 6 months into the future. So it’s really helpful to end up with good clean code so yit’s easier to understand.
Another key benefit to writing “cleaner” code is that its generally easier to extend and otherwise modify in the future. When code is initially written it’s often impossible to tell if it will be reused in some way elsewhere. A familiar scenario is that you stop developing a piece of code for a while, and put it to one side. Maybe it’s not needed any more, or perhaps a project has finished. You forget about it, until suddenly, there’s a need to use the code again. Maybe all of it needs to be reused in another project, or maybe just a part of it. However, you come back to your code, and it’s a mess you can’t understand. But by spending a little time now to write good code while you understand it, you can save yourself (and possibly others) a lot of time later!
Does my Code Smell?
Developers sometimes talk about “code smells”. Code smells are cursory indications from looking at the source code that a piece of code may have some deeper issues. And looking at this code, it smells pretty terrible. For example, we can see that there is inconsistent spacing, with lines bunched together in some places, and very spread out in others. This doesn’t engender a great deal of confidence that the code will work as we expect, and it raises the question that if the style of the code appears rushed, what else has been rushed? How about the design of the code? Something to bear in mind when writing code!
Running the Example Code
Now despite the issues with the code, does it work? Let’s find out. Within the shell, in the root directory of the repository, run the code as follows:
OUTPUT
Max temperature in Celsius 14.73888888888889 Kelvin 287.88888888888886
Max temperature in Celsius 14.777777777777779 Kelvin 287.92777777777775
Max temperature in Celsius 14.61111111111111 Kelvin 287.76111111111106
Max temperature in Celsius 13.838888888888887 Kelvin 286.9888888888889
Max temperature in Celsius 15.477777777777778 Kelvin 288.62777777777774
Max temperature in Celsius 14.972222222222225 Kelvin 288.1222222222222
Max temperature in Celsius 14.85 Kelvin 288.0
Max temperature in Celsius 16.33888888888889 Kelvin 289.4888888888889
Max temperature in Celsius 16.261111111111113 Kelvin 289.4111111111111
Max temperature in Celsius 16.33888888888889 Kelvin 289.4888888888889
And we can see that the code does indeed appear to work, with Celsius and Kelvin values being printed to the terminal. But how can we improve its readability? We’ll use a special tool, called a code linter, to help us identify these sorts of issues with the code.
- No one writes readable, well designed and well formatted code all the time
- Writing clear and readable code helps others - as well as yourself in the future - to understand, modify and extend your code more easily
- A code smell is a cursory indication that a piece of code may have underlying issues
Content from Analysing Code using a Linter
Last updated on 2025-10-23 | Edit this page
Estimated time: 10 minutes
Overview
Questions
- What tools can help with maintaining a consistent code style?
- How can I keep dependencies between different code projects separate?
- How can we automate code style checking?
Objectives
- Use Pylint to verify a program’s adherence to an established Python coding style convention
- Describe the benefits of a virtual environment
- Create and use a virtual environment to manage Python dependencies separately for our example code
- Install the Pylint static code analysis tool as a VSCode extension
- Use the Pylint extension to identify deeper potential issues and errors
- List the various types of issue messages that are output from Pylint
- Fix an issue identified by Pylint and re-run Pylint to ensure it is resolved
Installing a Code Linter
The first thing we need to do is install Pylint, a very well established tool for statically analysing Python code.
Now fortunately, Pylint can be installed as a Python package, and we’re going to create what’s known as a virtual environment to hold this installation of Pylint.
Installing Python Packages
Who has installed a Python package before, using the program
pip? Who has created and used a Python virtual environment
before?
Benefits of Virtual Environments
Virtual environments are an indispensible tool for managing package dependencies across multiple projects, and could be a whole topic itself. In the case of Python, the idea is that instead of installing Python packages at the level of our machine’s Python installation, which we could do, we’re going to install them within their own “container”, which is separate to the machine’s Python installation. Then we’ll run our Python code only using packages within that virtual environment.
There are a number of key benefits to using virtual environments:
- It creates a clear separation between the packages we use for this project, and the packages we use other projects.
- We don’t end up with a machine’s Python installation containing a clutter of a thousand different packages, where determining which packages are used for which project often becomes very time consuming and prone to error.
- Since we are sure what our code actually needs as dependencies, it becomes much easier for someone else (which could be a future version of ourselves) to know what these dependencies are and install them to use our code.
- Virtual environments are not limited to Python; for example there are similar tools for available for Ruby, Java and JavaScript.
Setting up a Virtual Environment
Let’s now create a Python virtual environment and make use of it. Make sure you’re in the root directory of the repository, then type
Here, we’re using the built-on Python venv module -
short for virtual environment - to create a virtual environment
directory called “venv”. We could have called the directory anything,
but naming it venv (or .venv) is a common
convention, as is creating it within the repository root directory. This
makes sure the virtual environment is closely associated with this
project, and not easily confused with another.
Once created, we can activate it so it’s the one in use:
BASH
[Linux] source venv/bin/activate
[Mac] source venv/bin/activate
[Windows] source venv/Scripts/activate
You should notice the prompt changes to reflect that the virtual environment is active, which is a handy reminder. For example:
OUTPUT
(venv) $
Who has successfully created and activated their virtual environment?
Now it’s created, let’s take a look at what’s in this virtual environment at this point.
OUTPUT
Package Version
---------- -------
pip 22.0.2
setuptools 59.6.0
We can see this is essentially empty, aside from some default packages that are always installed. Note that whilst within this virtual environment, we no longer have access to any globally installed Python packages.
Installing Pylint into our Virtual Environment
The next thing we can do is install any packages needed for this codebase. As it turns out, there isn’t any needed for the code itself, but we wish to use pylint, and that’s a python package.
What is Pylint?
Pylint is a tool that can be run from the command line or via IDEs like VSCode, which can help our code in many ways:
- Ensure consistent code style : whilst in-IDE context-sensitive highlighting such as that provided by VSCode, it helps us stay consistent with established code style standards such as (PEP 8) as we write code by highlighting infractions.
- Perform basic error detection: Pylint can look for certain Python type errors.
- Check variable naming conventions: Pylint often goes beyond PEP 8 to include other common conventions, such as naming variables outside of functions in upper case.
- Customisation: you can specify which errors and conventions you wish to check for, and those you wish to ignore.
So we can install pylint library into our virtual
environment as:
Now if we check the packages, we see:
OUTPUT
Package Version
----------------- -------
astroid 3.3.9
dill 0.3.9
isort 6.0.1
mccabe 0.7.0
pip 22.0.2
platformdirs 4.3.7
pylint 3.3.6
setuptools 59.6.0
tomli 2.2.1
tomlkit 0.13.2
typing_extensions 4.13.1
So in addition to Pylint, we see a number of other dependent packages installed that are required by it.
We can also deactivate our virtual environment:
You should see the “(venv)” prefix disappear, indicating we have returned to our global Python environment. Let’s reactivate it since we’ll need it to use pylint.
Analysing our Code using a Linter
Let’s point Pylint at our code and see what it reports:
We run this, and it gives us a report containing issues it has found with the code, and also an overall score.
OUTPUT
************* Module climate_analysis
climate_analysis.py:9:35: C0303: Trailing whitespace (trailing-whitespace)
climate_analysis.py:9:0: C0325: Unnecessary parens after '=' keyword (superfluous-parens)
climate_analysis.py:1:0: C0114: Missing module docstring (missing-module-docstring)
climate_analysis.py:4:0: C0103: Constant name "shift" doesn't conform to UPPER_CASE naming style (invalid-name)
climate_analysis.py:5:0: C0103: Constant name "comment" doesn't conform to UPPER_CASE naming style (invalid-name)
climate_analysis.py:6:15: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
climate_analysis.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
climate_analysis.py:8:0: C0103: Function name "FahrToCelsius" doesn't conform to snake_case naming style (invalid-name)
climate_analysis.py:8:18: W0621: Redefining name 'fahr' from outer scope (line 20) (redefined-outer-name)
climate_analysis.py:9:4: W0621: Redefining name 'celsius' from outer scope (line 21) (redefined-outer-name)
climate_analysis.py:11:0: C0116: Missing function or method docstring (missing-function-docstring)
climate_analysis.py:11:0: C0103: Function name "FahrToKelvin" doesn't conform to snake_case naming style (invalid-name)
climate_analysis.py:11:17: W0621: Redefining name 'fahr' from outer scope (line 20) (redefined-outer-name)
climate_analysis.py:12:4: W0621: Redefining name 'kelvin' from outer scope (line 22) (redefined-outer-name)
climate_analysis.py:6:15: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
climate_analysis.py:1:0: W0611: Unused import string (unused-import)
------------------------------------------------------------------
Your code has been rated at 0.59/10 (previous run: 0.59/10, +0.00)
For each issue, it tells us:
- The filename
- The line number and text column the problem occurred
- An issue identifier (what type of issue it is)
- Some text describing this type of error (as well as a shortened form of the error type)
You’ll notice there’s also a score at the bottom, out of 10. Essentially, for every infraction, it deducts from an ideal score of 10. Note that it is perfectly possible to get a negative score, since it just keeps deducting from 10! But we can see here that our score appears very low - 0.59/10, and if we were to now resolve each of these issues in turn, we should get a perfect score.
Identifying and Fixing an Issue
We can also ask for more information on an issue identifier. For example, we can see at line 9, near column 35, there is a trailing whitespace
OUTPUT
:trailing-whitespace (C0303): *Trailing whitespace*
Used when there is whitespace between the end of a line and the newline. This
message belongs to the format checker.
Which is helpful if we need clarification on a particular message.
If we now edit the file, and go to line 9, column 35, we can see that there is an unnecessary space.
Who’s managed to run pylint on the example code?
Let’s fix this issue now by removing the space, save the changed file, and then re-run pylint on it.
OUTPUT
------------------------------------------------------------------
Your code has been rated at 1.18/10 (previous run: 0.59/10, +0.59)
And we see that the C0303 issue has disappeared and our
score has gone up! Note that it also gives us a comparison against our
last score.
As a gentle warning: it can get quite addictive to keep increasing your score, which might well be the point!
So looking at the issue identifiers, e.g. C0303, what do
the C, W, R prefix symbols
mean?
At the end, we can see a breakdown of what they mean:
-
Iis for informational messages -
Cis for a programming standards violation. Part of the code is not conforming to the normally accepted conventions of writing good code (e.g. things like variable or function naming) -
Rfor a need to refactor, due to a “bad code smell” -
Wfor warning - something that isn’t critical should be resolved -
Efor error - so pylint think’s it’s spotted a bug (useful, but don’t depend on this to find errors!) -
Ffor a fatal pylint error
So if we run it again on our code:
OUTPUT
************* Module climate_analysis
climate_analysis.py:9:0: C0325: Unnecessary parens after '=' keyword (superfluous-parens)
climate_analysis.py:1:0: C0114: Missing module docstring (missing-module-docstring)
climate_analysis.py:4:0: C0103: Constant name "shift" doesn't conform to UPPER_CASE naming style (invalid-name)
climate_analysis.py:5:0: C0103: Constant name "comment" doesn't conform to UPPER_CASE naming style (invalid-name)
climate_analysis.py:6:15: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
climate_analysis.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
climate_analysis.py:8:0: C0103: Function name "FahrToCelsius" doesn't conform to snake_case naming style (invalid-name)
climate_analysis.py:8:18: W0621: Redefining name 'fahr' from outer scope (line 20) (redefined-outer-name)
climate_analysis.py:9:4: W0621: Redefining name 'celsius' from outer scope (line 21) (redefined-outer-name)
climate_analysis.py:11:0: C0116: Missing function or method docstring (missing-function-docstring)
climate_analysis.py:11:0: C0103: Function name "FahrToKelvin" doesn't conform to snake_case naming style (invalid-name)
climate_analysis.py:11:17: W0621: Redefining name 'fahr' from outer scope (line 20) (redefined-outer-name)
climate_analysis.py:12:4: W0621: Redefining name 'kelvin' from outer scope (line 22) (redefined-outer-name)
climate_analysis.py:6:15: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
climate_analysis.py:1:0: W0611: Unused import string (unused-import)
------------------------------------------------------------------
Your code has been rated at 1.18/10 (previous run: 1.18/10, +0.00)
We can see that most of our issues are do to with coding conventions.
- Virtual environments help us maintain dependencies between different code projects separately, avoiding confusion between which dependencies are strictly required for a given project
- One method to create a Python virtual environment is to use
python -m venv venvto generate a virtual environment in the current directory calledvenv - Code linters such as Pylint help to analyse and identify deeper issues with our code, including potential run-time errors
- Pylint outputs issues of different types, including informational messages, programming standards violations, warnings, and errors
- Pylint outputs an overall score for our code based on deductions from a perfect score of 10
Content from Advanced Linting Features
Last updated on 2025-10-23 | Edit this page
Estimated time: 10 minutes
Overview
Questions
- What can I do to increase the detail of Pylint reports?
- How can I reduce unwanted messages from Pylint?
- How can I use static code analysis tools within VSCode?
Objectives
- Use Pylint to produce a verbose report showing number of occurrences of encountered message types
- Fix an issue within our code to increase our Pylint score
- Specify message types to Pylint that we don’t want reported
- Install a Pylint extension into VSCode
More Verbose Reporting
We can also obtain a more verbose report by adding
--reports y to the command, which gives us a lot more
detail:
Here’s a part of that output:
OUTPUT
...
Messages
--------
+---------------------------+------------+
|message id |occurrences |
+===========================+============+
|redefined-outer-name |4 |
+---------------------------+------------+
|invalid-name |4 |
+---------------------------+------------+
|missing-function-docstring |2 |
+---------------------------+------------+
|unused-import |1 |
+---------------------------+------------+
|unspecified-encoding |1 |
+---------------------------+------------+
|superfluous-parens |1 |
+---------------------------+------------+
|missing-module-docstring |1 |
+---------------------------+------------+
|consider-using-with |1 |
+---------------------------+------------+
...
For those doing activity, who’s managed to run this command?
It gives you some overall statistics, plus comparisons with the last time you ran it, on aspects such as:
- How many modules, classes, methods and functions were looked at
- Raw metrics (which we’ll look at in a minute)
- Extent of code duplication (none, which is good)
- Number of messages by category (again, we can see that it’s mainly convention issues)
- A sorted count of the messages we received
Looking at raw metrics, we can see that it breaks down our program into how many lines are code lines, Python docstrings, standalone comments, and empty lines. This is very useful, since it gives us an idea of how well commented our code is. In this case - not very well commented at all! For normal comments, the usually accepted wisdom is to add them to explain why you are doing something, or perhaps to explain how necessarily complex code works, but not to explain the obvious, since clearly written code should do that itself.
Increasing our Pylint Score - Adding a Docstring
Docstrings
Who’s familiar with Python docstrings?
Docstrings are a special kind of comment for a function, that explain what the function does, the parameters it expects, and what is returned. You can also write docstrings for classes, methods, and modules, but you should usually aim to add docstring comments to your code wherever you can, particularly for critical or complex functions.
Let’s add one to our code now, within the
fahr_to_celsius function.
PYTHON
"""Convert fahrenheit to Celsius.
:param fahr: temperature in Fahrenheit
:returns: temperature in Celsius
"""
Re-run pylint command - can see we have one less
docstring error, and a slightly higher score.
If you’d like to know more about docstrings and commenting, there’s an in-depth RealPython tutorial on these and the different ways you can format them.
Ignoring Issues
We can instruct pylint to ignore any particular types of issues, which is useful if they are not seen as important or pedantic, or we need to see other types more clearly. For example, to ignore any unused imports:
Or, to disable all issues of type “warning”:
This can be particularly useful if we wish to ignore particularly pedantic rules, such as long line lengths over 100 characters.
Challenge
Edit the climate_analysis.py file and add in a comment
line that exceeds 100 characters. Then re-run pylint and determine the
issue identifier for this message, and re-run pylint again disabling
this specific issue.
OUTPUT
************* Module climate_analysis
climate_analysis.py:3:0: C0301: Line too long (111/100) (line-too-long)
climate_analysis.py:17:0: C0325: Unnecessary parens after '=' keyword (superfluous-parens)
climate_analysis.py:1:0: C0114: Missing module docstring (missing-module-docstring)
...
We can see that the identifier is C0301, so:
However, if we wanted to ignore this issue for the foreseeable future, typing this in every time would be tiresome. Fortunately we can specify a configuration file to pylint which specifies how we want to interpret issues.
We do this by first using pylint to generate a default
.pylintrc file. It directs this as output to the shell, so
we need to redirect it to a file to capture it. Ensure you are in the
repository root directory, then:
If you edit this generated file you’ll notice there are many things
we can specify to pylint. For now, look for disable= and
add C0301 to the list of ignored issues already present
that are separated by commas, e.g.:
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable=C0301,
raw-checker-failed,
bad-inline-option,
locally-disabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
use-implicit-booleaness-not-comparison-to-string,
use-implicit-booleaness-not-comparison-to-zero,
use-symbolic-message-instead
Every time you re-run it now, the C0301 issue will not
be present.
Using Pylint within VSCode
The good news is that if you’re using the VSCode IDE, we can also (or
alternatively) install a Python linter in VSCode to give us this code
analysis functionality, by installing the Pylint extension. Select the
Extensions icon and this time search for
Pylint, the one by Microsoft, and click
Install.
Going back to our code you should now find lots of squiggly underlines of various colours.
I don’t see any Squiggly Underlines!!
If you happen to not see any squiggly underlines in the editor, it
could be the linter extension hasn’t looked at your code yet. In order
to trigger the linter to show us further issues, try saving the file to
trigger the linter to do this. So go to File then
Save on the menu bar, and you should now see a lot of
squiggly underlines in the code.
These squiggly lines indicate an issue, and by hovering over them, we
can see details of the issue. For example, by hovering over the
variables shift or comment - we can see that
the variable names don’t conform to what’s known as an
UPPER_CASE naming convention. Simply, the linter has
identified these variables as constants, and typically, these are in
upper case. We should rename them, e.g. SHIFT and
COMMENT. But following this, we also need to update the
reference to comment in the code so it’s also upper case.
Now if we save the file selecting File then
Save, we should see the linter rerun, and those highlighted
issues disappear.
We can also see a comprehensive list of all the issues found, by
opening a code Problems window. In the menu, go to
View then Problems, and then you’ll see a
complete list of issues which we can work on displayed in the pane at
the bottom of the code editor. We don’t have to address them, of course,
but by following them we bring our code style closer to a commonly
accepted and consistent form of Python.
Summary
Code linters like pylint help us to identify problems in our code, such as code styling issues and potential errors, and importantly, if we work in a team of developers such tools help us keep our code style consistent. Attempting to understand a code base which employs a variety of coding styles (perhaps even in the same source file) can be remarkably difficult.
But there are some aspects we should be careful of when using linters and interpreting their results:
- They don’t tell us that the code actually works and they don’t tell us if the results our code produces are actually correct, so we still need to test our code.
- They don’t give us any Idea of whether it’s a good implementation, and that the technical choices are good ones. For example, this code contains functions to conduct temperature conversions, but it turns out there’s a number of well-maintained Python packages that do this (e.g. pytemperature)so we should be using a tried and tested package instead of reinventing the wheel.
- They also don’t tell us if the implementation is actually fit for purpose. Even if the code is a good implementation, and it works as expected, is it actually solving the intended problem?
- They also don’t tell us anything about the data the program uses which may have its own problems.
- A high score or zero warnings may give us false confidence. Just because we have reached a 10.00 score, doesn’t mean the code is actually good code, just that it’s likely well formatted and hopefully easier to read and understand.
So we have to be a bit careful. These are all valid, high-level questions to ask while you’re writing code, both as a team, and also individually. In the fog of development, it can be surprisingly easy to lose track of what’s actually being implemented and how it’s being implemented. A good idea is to revisit these questions regularly, to be sure you can answer them!
However, whilst taking these shortcomings into account, linters are a very low effort way to help us improve our code and keep it consistent.
- Use the
--reports yargument on the command line to Pylint to provide verbose reports - Instruct Pylint to ignore messages on the command line using the
--disable=argument followed by comman-separated list of message identifiers - Use
pylint --generate-rcfile > .pylintrcto generate a pre-populated configuration file for Pylint to edit to customise Pylint’s behaviour when run within a particular directory - Pylint can be run on the command line or used within VSCode
- Using Pylint helps us keep our code consistent, particularly across teams
- Don’t use Pylint feedback and scores as the only means to judge code quality