Comments In Python
When diving into Python, mastering the art of writing clean, readable code is as important as the logic behind it. This is where comments come into play. Comments in Python aren’t just notes; they are a developer’s way of communicating intent, clarifying complex logic and ensuring code is understandable to both others and your future self. In this article, we will explore how to use comments effectively, turning your Python code into a more structured, well-documented masterpiece. Let’s unlock the power of Python comments to enhance both code quality and collaboration.
Table of Content
- Comments
- Indentation in python
- Container types
- Mutable and immutable types
- Functions and methods
- Importing
- Revisiting interactive mode
- Errors
- PEP8
Comments
In your program file, you can not only write Python code but can also
include notes to explain the code. This becomes more important if your
programs are lengthy and complicated and there is a team of programmers
working together. When you are developing a program, you are deep into it
and have an understanding of how it works. However, upon revisiting the
code later, you might forget how you made things work. Understanding a
complicated program by just looking at the code is difficult; reading the
notes will help you understand the code faster and save you time. This is
also true for other fellow programmers who need to read and understand
your code.
These notes are called comments in programming languages. A comment is a
piece of text that is inserted in between the code to explain the purpose of
your code to other programmers or to yourself when you revisit the code.
Code that is properly documented with comments makes the program more
readable and understandable and so it is easier to maintain and update.
Comments are written only for human readers; they are ignored by the
interpreter, so they have no effect on the execution of the program.
In Python, a comment starts with a hash sign (#) and lasts till the end of the
current line. Any text after the # sign till the end of the line will not be
executed. The interpreter just ignores it. A comment can be written on a new
line or after a statement on the same line. The figure below shows a code snippet
that contains some comments.
Do not try to understand the code because many structures used in it have
not been introduced yet. The code is here just to illustrate how comments are
used to explain the purpose of the code. Comments should not be written for
code that is doing something obvious; such comments are unnecessary and
should be avoided.
If you need to write a multi-line comment (block comment), then you have
to precede each line with the # sign. In IDLE, you can easily comment
multiple lines by selecting those lines, going to the Format menu and
selecting Comment region.
In addition to documentation, there is another use of comments. You can use
comments to disable part of your program while testing or debugging.
Debugging is the process where you are trying to find out why the code is
not working. You can temporarily comment some parts of the program that
you think might be creating problems.
The code that is commented out will not be executed when you run your
program. So, if your program is not working as expected, then you can comment on a piece of code and see if the code runs fine. Text editors generally
have the facility of commenting out pieces of code, so you do not have to
manually put a # sign in front of each line that you want to disable. Later,
you can remove the commenting signs from your disabled code by choosing
the Uncomment option in your editor.
Indentation In Python
Indentation is the whitespace (spaces or tabs) that is present before the
beginning of a code line. In most of the languages, indentation is done just to
increase the readability, but in Python, it is very important. Python forces
programmers to structure their code through indenting. So, indentation is not
a matter of style, but a part of syntax in Python. Indentation of each line
matters; wrong indentation can result in either an indentation error or
incorrect behavior of your program.
Python uses indentation for grouping statements to form code blocks. In the
code snippet that we saw in section 2, we can see the code blocks being
defined with different indentations. Continuous statements with the same
indentation belong to the same code block. Higher levels of indentations
indicate nested code blocks. Unlike other languages, Python does not use
braces or words like begin or end to define the boundaries of blocks of code.
It uses indentation for this purpose. As we move through the chapters and
learn about different compound statements such as if..else, while, for, def,
etc., we will see how to use indentation for defining blocks.
The code that we have written till now is top-level code of the file; it is not
indented, which means that there should be no whitespace at the beginning
of the statement. So, till we get introduced to compound statements, we will
write all our code without any indentation. The following program will give
an indentation error if you try to execute it.
name = input('Enter name : ')
age = int(input('Enter age : '))
print(name, age)
The error is caused due to an unexpected indentation in the second
statement. The program will execute if you remove the two spaces present at the beginning of the second statement.
Container Types
In the next few sections, we will learn in detail about the built-in data
structures or collection types in Python lists, tuples, dictionaries and sets.
These are also called containers as they provide a way of combining and
organizing data. These data structures are used to hold different types of
objects. Here, are some examples of literals of these types.
- Lists (type list) [1, 2, 3, 4]
- Tuples (type tuple) (1, 2, 4, 5)
- Dictionaries (type dict) {’a’: 1, ’b’: 2, 'c’: 3}
- Sets (type set) {2, 3, 4, 6, 8}
Lists and tuples are sequence types in Python which means that they are
ordered collections of values. These types contain a left-to-right order
among the items that they contain. We can tell which one is the first element,
which is the second, which is the last and so on. In these types, the
contained items are accessed using their positions. Dictionaries are the
mapping type as they store objects by keys. In Python 3.6 and earlier
versions, dictionaries were unordered, but from version 3.7, they are
ordered. Sets are neither mapping nor sequences; they are just collections of
unique objects.
Mutable and Immutable Type
We know that each object has a type, an id, and a value. The type and id of
an object remain the same throughout the program; they cannot be changed.
Whether the contained value can be changed or not depends on the
mutability of the object.
Python types can be categorized as either mutable or immutable depending
on whether the value of an object of that type can be changed or not. If a
type is immutable, the value inside an object of that type cannot be changed.
You can never overwrite the value of an immutable object. If a type is mutable, then the value contained inside the object of that type can be
changed at run time. Here, are some immutable and mutable types in Python.
- Immutable - bool int float str tuple frozenset
- Mutable - list set dict
Mutable types support operations that can change the value inside the object
at run time, while immutable types do not provide any operation that can
change the value inside the object. The state of an immutable object is fixed
at the time of creation and cannot be modified later.
You need to keep in mind that mutability has nothing to do with the variable
names. Let us try to understand this. Suppose the variable name x refers to a
mutable object and the name a refers to an immutable object.
The object to which x is referring is a mutable object, so the value inside it
can be changed. We generally say that it can be changed in-place. The object
to which a is referring is an immutable object, so it will remain as it is
throughout its lifetime. You cannot overwrite it; it cannot be changed in-place.
The variable referencing any object can always be reassigned to a different
object; we can make x, or a refer to a different object. So, mutability is
associated with types and objects not with variables.
You need to clearly understand the difference between the terms rebinding a
variable and mutating an object. Rebinding a variable means making a
variable refer to a different object, and mutating an object means making in-place changes in that object. Only mutable objects can be mutated. In our
example, the variable a refers to an int object with value 56; the
operations like a = a + 3 seem to change the value, but remember this is
rebinding. int is an immutable type, so you cannot modify the value inside an object once it is created. You can only create a new object with a different
value. The value 56 inside the object is not changed to 59. Instead, a new
object with value 59 is created and refers to that object. So, any operation
on the immutable types that seems to modify the value results in the creation
of a new object with the modified value.
If a variable refers to an immutable object, you can see changes in that
variable only by rebinding that variable. If a variable refers to a mutable
object, you can see changes in that variable by rebinding it or by making in-place changes in the object that it is referring to. In our example, we have
variable x referring to a list object and variable a referring to an int
object. We can see changes in x by rebinding x to a different object or by
changing in-place the list object that it is currently referring to. We can see
changes in a only when we rebind it to a different object.
Mutability matters when there are multiple references referring to an object.
Suppose we have three variables x, y, and z, that refer to a list object
and three variables a, b, and c that refer to an int object.
If we make any in-place changes to the list object through any of the
variables x, y or z, then that change will be visible in the other two
variables also because all three of them share the same object. In the case of
immutable objects, these types of side effects will not occur because they
cannot be changed in-place. This distinction is very important to understand and it will become clearer as we proceed through the sections and cover
some of the mutable and immutable types in detail.
Functions and Methods
We will talk about functions and methods in detail later, but since we will be
using built-in functions and methods in the next few chapters, you need to
have a general idea of what they are and how you can use them.
A function is a reusable piece of code with a name, and it can perform
certain operations for you. You can give it some values called arguments; it
performs some work for you, and it might give you a value back. The built-in functions are the functions that are already written for us and are always
available, so we can easily use them. We have already used some built-in
functions, like print, input, type and id. We know that to call them,
we need to write their name followed by parentheses which can include
some arguments. Arguments are values that provide some information to the
function for performing its work. If the function doesn’t need any arguments,
then the parentheses remain empty. Here, are some examples of built-in
functions.
- abs(x) - Returns absolute value of x
- bin(x) - Returns binary equivalent of x
oct(x) - Returns octal equivalent of x - hex(x) - Returns hexadecimal equivalent of x
- max(a, b, c, ……) - Returns maximum value among the provided
arguments - min(a, b, c, ……) - Returns minimum value among the provided
arguments
A method is like a function, but it is specific to a type and we access it by
using a dot. To call a method, we write the variable name or a literal
followed by a dot, then the method name and then the parentheses which
can include arguments.
'hello'.upper()
list1.append(10)
Here, we are calling the method upper on a string literal, and we are calling
the method append on a variable named list1 that refers to a list
object.
Functions are not specific to any type, so they are called independently
without the dot syntax. You can think of functions as generic operations that
can work with multiple types. For example, the built-in function len can be
used to find the length of a string, list, or a dictionary. Methods are type
specific operations that are attached to types and can act on an object of a
specific type only. For example, the method upper can act only on an
object of type str, and the method append can act only on an object of
type list. We will discuss most of the methods related to the types that we
will see in the coming sections.
A type defines many methods and it is not possible to remember all methods
associated with a particular type. So whenever required, you can go to the
interactive prompt and get a listing of all the methods. To know about the
methods available for a data type, just type dir(typename) on the
interactive prompt, and it will show you all the methods available for that
type. For example, to see all the methods for the list type, we can write.
>>> dir(list)
Output
['__add__', '__class__', '__class_getitem__',
'__contains__', '__delattr__', '__delitem__',
'__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__getitem__',
'__gt__', '__hash__', '__iadd__', '__imul__',
'__init__', '__init_subclass__', '__iter__',
'__le__', '__len__', '__lt__', '__mul__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__reversed__', '__rmul__',
'__setattr__', '__setitem__', '__sizeof__',
'__str__', '__subclasshook__', 'append', 'clear',
'copy', 'count', 'extend', 'index', 'insert',
'pop', 'remove', 'reverse', 'sort']
This is the result that we get. There will be lots of methods with leading and
trailing underscores, and these methods represent the implementation details
of the type and help in customization. The methods towards the end are the
ones without any underscore, and these are the methods that we will be
mostly using.
This command shows you the names of methods. If you want to know more
about a particular method, you can use help. On the interactive prompt, write
help, then inside parentheses, write typename followed by a dot and then the
method name.
>>> help(list.append)
Output
Help on method_descriptor:
append(self, object, /)
Append object to the end of the list.
>>> help(str.upper)
Output
Help on method_descriptor:
upper(self, /)
Return a copy of the string converted to
uppercase.
Here, we are getting help on the append method of list type and the
upper method of string type.
These functions dir() and help() accept both the type name or a
variable name. So, suppose you have a variable s referring to a string object,
you can use dir and help on s also. If you write help(typename)
then it will show you the description of all the methods.
Importing
There are many predefined functions in the standard library that we can use
in our program, but unlike built-in functions, these functions are not
automatically available in our program. These functions are organized in
modules (Python files) and we have to import them to make them available
in our program. For example, the math module contains many mathematical
functions. The random module provides functions for randomization. In this code, we are importing and using sqrt and trunc functions
from the math module.
from math import sqrt, trunc
x = 34
y = 23.4
print(sqrt(34))
print(trunc(23.4))
Output
5.830951894845301
23
If you import a module by writing import modulename, then all the
names in that module can be used in your program, but they have to be
preceded by the module name and a dot.
import math
x = 34
y = 23.4
print(math.sqrt(34))
print(math.trunc(23.4))
We can import modules from the rich standard library and make use of lots
of pre-existing functionality and that is why the term 'batteries included' is
used for Python. You can see a list of standard library modules in the official
Python documentation and to know more about a module, import it on the
shell and use help on it.
>>> import math
>>> help(math)
To see all the available names in a module, you can use the dir function
after importing it.
>>> dir(math)
Output
['__doc__', '__loader__', '__name__',
'__package__', '__spec__', 'acos', 'acosh', 'asin',
'asinh', 'atan', 'atan2', 'atanh', 'cbrt', 'ceil',
'comb', 'copysign', 'cos', 'cosh', 'degrees',
'dist', 'e', 'erf', 'erfc', 'exp', 'exp2', 'expm1',
'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose',
'isfinite', 'isinf', 'isnan', 'isqrt', 'lcm',
'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2',
'modf', 'nan', 'nextafter', 'perm', 'pi', 'pow',
'prod', 'radians', 'remainder', 'sin', 'sinh',
'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp']
To get help on a specific name from the module, use help on that name.
>>> import math
>>> help(math.floor)
Output
Help on built-in function floor in module math:
floor(x, /)
Return the floor of x as an Integral.
Revisiting Interactive Mode
We know that when we enter a statement on the shell prompt, it will be
executed and when we enter an expression, it will be evaluated and its
value will be printed. This automatic printing is there only in interactive
mode. In script mode, you need to use the print function to print the value
of expressions. The print function works in the interactive mode also, but
is not required so you can save some typing.
>>> a = 10
>>> a
Output
10
>>> print(a)
Output
10
A single underscore is a valid identifier name in Python and in scripts, it is
used to ignore values, as we will see later. In interactive mode, a single
underscore ( _ ) is a special variable name that stores the result of the last
expression that was evaluated. You can use this variable in another
expression on the prompt.
>>> a = 5
>>> a + 2
Output
7
>>> _
Output
7
>>> _ + 5
Output
12
When you enter multiline statements on the interactive prompt, the prompt
string changes from ">>>" to "….".
>>> total_marks = marks_science + marks_maths \
.+ marks_english + marks_socials \
+ grace_marks
>>> months = [ 'January', 'February', 'March',
'April', 'May', 'June', 'July', 'August',
'September', 'October', 'November','December']
So, when you type something that occupies more than one line, the prompt
changes to three dots.
While experimenting in the interactive mode, you would often make
mistakes and get errors. In those cases, you would want to edit and rerun
your previous command. You can do this without retyping the previous
command by making use of the command history. Each interactive session
maintains a history of all the commands that you type at the shell prompt.
You can scroll through these commands by pressing "Alt+P" for the
previous command and "Alt+N" for the next command. On Mac, you have
to use Command-P and Command-N. Up and down arrow keys can also be
used on some systems for scrolling through commands. By using arrow
keys, take the cursor on the desired command and then press Enter to select
that command. You can also click on a previous command and press Enter to
get that command on your prompt. Once you get a command displayed on
your prompt, you can either edit it and then execute it, or you can just
execute the command as it is.
We know that when a program is executed, its output appears in the shell
window. When the execution of the program is over, the Shell window
retains focus and displays a shell prompt. Now, you can explore the result of
the program execution on this prompt. For example, you can see the final
values of variables you defined in the program. Any names that you had
defined in the program would be available in the Shell window after the
execution of the program.
Errors
As you start writing programs, you will encounter many errors in your
programs. Understanding and fixing errors is a part of the learning process.
It improves our understanding of the language and problem-solving skills.
We can broadly categorize errors into three types, syntax errors, run time
errors and logical errors.
Syntax is a set of rules that define how the code instructions should be
written in a language. In the previous section, we saw that our source code is
compiled before being executed by PVM. During the compilation step, the
compiler checks the syntax of each instruction and translates it to bytecode.
When it finds anything written in the wrong syntax, it stops the translation
and displays an error message. These errors are called syntax errors or
parsing errors and they occur due to the incorrect syntax of the code. For
example, you might miss a colon or a quote or use an unbalanced pair of
parentheses. When there is a syntax error in your program, and you try to run
the program, IDLE shows a dialog box, and it also highlights the location
where the syntax error is detected in your program. You need to fix the error
by making changes in your code and running the program again. As a
beginner, you will find yourself making many syntax errors, but as you get
used to the language, their frequency will reduce. It is generally not very
difficult to identify and remove these errors from your program. Some
development environments not IDLE underline the syntax errors as you
type the code.
If there are no syntax errors, the byte code is generated and your program
enters run time. The byte code goes through the Python Virtual Machine which executes it by converting it to machine code. Run time is the time
when your program is executing; during this time, your program will interact
with the user and might be connected with multiple external resources. If an
error occurs during this time, then the execution of the program stops
immediately and it is terminated with an error message. Any error that
occurs at this run time is called a run time error. There are some run time
errors that are caused due to some mistake in your code, and they can be
removed by modifying your code. Some run time errors occur due to
unusual events at run time and they are not under the control of your
program. To handle them, you have to write the error handling code.
Logical errors occur when your program runs smoothly and gives you the
output, but the output that it gives is not what was intended, so your program
works, but it doesn’t do what you expect it to do. These errors occur due to
the wrong logic of the code that you have written. The problem is not with
the code. The program does exactly what it has been told to do. The problem
is that the programmer was not able to communicate properly the solution in
the form of code, or maybe the solution that the programmer has come up
with is not correct. It could be due to things like a missing assignment, the
use of a wrong operator, or an incorrect algorithm. These types of errors are
not reported by the interpreter. The programmer has to identify them, so
these errors are the most difficult to detect and remove. You have to examine
your code and debug the program, and at times, take the help of a debugger.
PEP8
Python Enhancement Proposals are documents that describe a new
Python features or provides information to the community. There are many
PEPs that are listed in PEP0 document, which is the index of PEPs and can
be accessed by clicking the link below. Of these PEPs, the most
useful for Python programmers is PEP8, which is a style guide for writing
python code.
PEP8 was written by Guido van Rossum, Barry Warsaw, and Nick Coghlan
in 2001. You can read it online by clicking the link below. This
document provides various coding conventions and best practices to write
readable and consistent code in Python. According to Guido van Rossum,
"Code is read much more often than it is written" and according to Zen of
Python, "Readability counts." Readability and consistency are important because the code is written once but read many times by different people for
various reasons, like collaborating on a project or debugging and adding new
features. Writing PEP8 compliant code will make it easier for you and others
to read and understand your Python code.
The guidelines in the document are only recommendations; if you write code
that does not conform to PEP8, your code will still work as long as it follows
the syntax of the language but might not be considered professional by the
Python community. Therefore, it is good to be aware of the best practices
and develop a habit of writing code that adheres to the community
guidelines.
The PEP8 document includes coding conventions for indentation,
white spaces, naming things and other coding constructs that we have yet to
learn. We will see the conventions as we get introduced to the coding
structures. However, I would recommend you to read the document at least
once. There are many tools and IDEs that will automatically format your
code according to PEP8.
Code bundle here:
https://github.com/codeaihub1998/Ultimate_Python_1-to-21
If you read this article till the end, please consider the following:
- Follow the author to get updates of upcoming articles 🔔
- If you like this article, please consider a clap 👏🏻
- Highlight that inspired you
- If you have any questions regarding this article, please comment your precious thoughts 💭
- Share this article by showing your love and support ❤️