DEV Community

Adejumo Ridwan Suleiman
Adejumo Ridwan Suleiman

Posted on • Originally published at adejumoridwan.hashnode.dev on

9 Things You Do That Shows You Are Not A Professional Python Developer

Photo by Timothy Dykes on Unsplash

Show me your code and I will tell you who you are.

This article will fix the bad habits you have stuck to over the years or brought from other programming languages.

Manual String Formatting

Most of the time you see beginner Pythonistas using the + sign when combining two strings.

>>> name = "Ridwan"
>>> age = "22"
>>> print("My Name is " + name + " and I am " + age + " years old")
My Name is Ridwan and I am 22 years old

Enter fullscreen mode Exit fullscreen mode

Instead of using the + sign, use the f string which makes your code readable, concise, and less prone to errors.

>>> print(f"My Name is {name} and I am {age} years old")
My Name is Ridwan and I am 22 years old

Enter fullscreen mode Exit fullscreen mode

Using Default Mutable Arguments

In Python, anytime you pass a mutable value as an argument in a function, the default argument is mutated anytime the function is called. These mutable arguments are usually lists or dictionaries.

Look at the example below;

>>> def append(n, l=[]):
... l.append(n)
... return l
...

Enter fullscreen mode Exit fullscreen mode

After defining the append function with a mutable argument l = [], anytime you call the function with a value of n, it changes the default value of l.

>>> l1 = append(0)
>>> l1
[0]

Enter fullscreen mode Exit fullscreen mode

When next you call the function with a different value of n, you are going to see the previous value you used appended to the empty list argument.

>>> l2 = append(1)
>>> l2
[0, 1]

Enter fullscreen mode Exit fullscreen mode

You can solve this problem by rewriting the code as:

>>> def append(n, l = None):
... if l is None:
... l = []
... l.append(n)
... return l
...
>>> l1 = append = [0]
>>> l2 = append = [1]
>>> l1,l2
([0], [1])

Enter fullscreen mode Exit fullscreen mode

Now the argument l is set to None, anytime the function is called even if l is mutated, it is reassigned as None and then given the value of an empty list.

Not Using Comprehensions

Python comprehensions provides you a short and concise way of way of constructing sequences, last time I checked, Python supports 4 types of comprehension;

  • List Comprehensions

  • Dictionary Comprehensions

  • Set Comprehensions

  • Generator Comprehensions

You can read more about them here.

The code below divides the values in a dictionary by 2,

>>> numbers = {}
>>> for i in range(10):
... numbers[i] = i/2
...
>>> numbers
{0: 0.0, 1: 0.5, 2: 1.0, 3: 1.5, 4: 2.0, 5: 2.5, 6: 3.0, 7: 
3.5, 8: 4.0, 9: 4.5}

Enter fullscreen mode Exit fullscreen mode

The above code can be written in a single line as,

>>> {i: i/2 for i in range(10)}
{0: 0.0, 1: 0.5, 2: 1.0, 3: 1.5, 4: 2.0, 5: 2.5, 6: 3.0, 7: 
3.5, 8: 4.0, 9: 4.5}

Enter fullscreen mode Exit fullscreen mode

So stop making life difficult for yourself and start using comprehension.

Checking for Equality instead of Identity

Given,

a = [1, 2, 3]
b = [1, 2, 3]

Enter fullscreen mode Exit fullscreen mode

If I ask you to check if the two variables are identical, the first thing to come to your mind is,

>>> a == b
True

Enter fullscreen mode Exit fullscreen mode

The thing is that you need to know the difference between Identity and Equality.

Two variables can be equal but not identical.

If you check the memory addresses of a and b,

>>> id(a), id(b)
(1838093945856, 1838093487488)

Enter fullscreen mode Exit fullscreen mode

You can see that they both have different addresses despite the fact that they have the same object.

This is the reason why, when you run,

>>> a == b
True

Enter fullscreen mode Exit fullscreen mode

You get True, but when you run

>>> a is b
False

Enter fullscreen mode Exit fullscreen mode

You get False, a and b are equal but not identical.

In the case where you have,

>>> c = [1,2,3]
>>> d = c
>>> id(c), id(d)
(1838089019712, 1838089019712)

Enter fullscreen mode Exit fullscreen mode

You can see, c and d are both equal and identical, the object in c is also assigned to d.

>>> c == d
True
>>> c is d
True

Enter fullscreen mode Exit fullscreen mode

This implies c and d have both the same value and memory addresses.

Hence you can say c is identical and equal to d.

All this epistle is to make you know the difference between is and ==, the former is used in checking identity while the latter is used in checking equality.

All Identical variables are equal but not all Equal variables are identical

Not Using Tuple Unpacking

Anytime you create a tuple in Python, it is known as packing a tuple,

>>> a_tuple = 1,2,3
>>> a_tuple
(1, 2, 3)

Enter fullscreen mode Exit fullscreen mode

These values can be extracted back into various variables by unpacking

>>> x = a_tuple[0]
>>> y = a_tuple[1]
>>> z = a_tuple[2]
>>> print(x, y, z)
1, 2, 3

Enter fullscreen mode Exit fullscreen mode

Instead of unpacking the elements in a tuple using multiple lines of code, you can do it in a single line of code.

>>> x,y,z = a_tuple
>>> print(x, y, z)
1, 2, 3

Enter fullscreen mode Exit fullscreen mode

Creating Your Own Index Counter Variable

This one is common from those coming from other programming languages, you are asked to create a index counter variable and you type something like;

>>> a_list = [1,2,3,4,5,6,7,8,9,10]
>>> index = 0
>>> for elem in a_list:
... print(index, elem)
... index += 1
...
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

Enter fullscreen mode Exit fullscreen mode

Instead, use the enumerate function to make your code look Pythonic;

>>> for index, elem in enumerate(a_list):
... print(index, elem)
...
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

Enter fullscreen mode Exit fullscreen mode

Using Print Statement Instead of the Logging Module

This might not matter in small projects, but will surely help you in larger projects.

Instead of littering your code with print statements, use the logging instead.

>>> print('This is a warning message')
This is a warning message
>>> print('This is an error message')
This is an error message
>>> print('This is a critical message')
This is a critical message

Enter fullscreen mode Exit fullscreen mode

Logging helps display useful messages to your users to add more context and understanding to what is happening in the code base.

>>> import logging
>>> logging.warning('This is a warning message')
WARNING:root:This is a warning message
>>> logging.error('This is an error message')
ERROR:root:This is an error message
>>> logging.critical('This is a critical message')
CRITICAL:root:This is a critical message

Enter fullscreen mode Exit fullscreen mode

Importing functions and classes in a named module with import *

This bad habit most at times is common among newbies.

Importing using import * corrupts your namespace by importing all the functions and classes from that named module into your code which is likely to conflict with the functions you define or functions of other libraries imported.

Not Following pep8

Most of us are guilty of this,

Before I get canceled 😂, I know some of my codes in this article might have broken the rules of PEP-8, but the truth is bitter and needs to be told, following PEP-8 style and guidelines makes it easier for others to read and understand your code.

Not Recommended

>>> def function():
... x = [1,2,3]
... y= [2,3,5]
... z = [1, 2,3]
...
>>> def value(x = 7):
... ...
...

Enter fullscreen mode Exit fullscreen mode

Recommended

>>> def function():
... x = [1, 2, 3]
... y = [2, 3, 5]
... z = [1, 2, 3]
...
>>> def number(x=7):
... ...
...

Enter fullscreen mode Exit fullscreen mode

To read more about the PEP-8 style and guidelines, check out this article.


Thanks for reading. Hope the article was worth your time.

Top comments (0)