Avoid those common python mistakes!

Everybody must start at some point, it is human to make mistakes, but what about a better work flow? it is what this post is about!

1st – Classes “Self” in methods

For most functions to work on python, we need some preparation, what I mean is not like an exercise but more like… knowing what you are doing.

So let’s get to the point, when making a function inside a class, their methods must have “self” on the first argument, it can be any variable name, really, but it will point to the class “self” making the readability bad, I mean, its not me who am saying about using self as a class, it is the own python dev team.

As a resume do this:

class MyClass:
    def __init__(self, value):
        self.value = value  # Use `self` to reference instance attributes
    
    def display(self):
        print(self.value)  # `self` is needed to access the instance attribute

Not this monstrosity:

class MyClass:
    def __init__(my_instance, value):
        my_instance.value = value  # using a different name instead of "self"

    def display(my_instance):
        print(my_instance.value)  # referring to the instance with "my_instance"

and even less this TypeError:

class MyClass:
    def __init__(self, value):
        self.value = value
    
    def display():  # Forgot `self`
        print(self.value)

obj = MyClass(10)
obj.display()  # TypeError: display() takes 0 positional arguments but 1 was given

2nd – Mutable Default argument.

Well in python, when working with lists of dictionaries, if you set it as a default argument it is not set each time you start the function, but only the first time, what does it mean? In this case instead of giving the right answer, it can lead to unexpected results, like so:

def add_element(lst=[]):
    lst.append(1)
    return lst
print(add_element())  # Output: [1]
print(add_element())  # Output: [1, 1] -- Unexpected!
print(add_element())  # Output: [1, 1, 1] -- The default list is shared

How to avoid it? it is fairy simple don’t use a list! use anything besides that and then make a list:

def add_element(lst=None):
    if lst is None:
        lst = []  # Create a new list if no list is provided
    lst.append(1)
    return lst

print(add_element())  # Output: [1]
print(add_element())  # Output: [1] -- Each call uses a fresh list
print(add_element([10, 20]))  # Output: [10, 20, 1] -- Custom input is handled properly

3rd – Re-using the same variables

A simple example of re-using one variable for the same purpose is like this one, that could lead to confusion:

# Case where variable names are re-used in the same scope
x = 10  # Initial assignment
x = 20  # Re-assignment with a different value

print(x)  # Output: 20 -- Original value is overwritten

But that is fairly obvious, and doesn`t matter too much, but on functions that is another way:

x = 10  # Outer scope variable

def update_x():
    x = 20  # New variable in inner scope
    print("Inner x:", x)  # Output: 20 -- This is a different variable from the outer one

update_x()

print("Outer x:", x)  # Output: 10 -- The outer scope variable is unchanged

Well, that is an obvious example, but as your code grows more and more, it will affect productivity a lot, especially if the function name is “updade_X” and it is directing to a function variable and not a global you have.

Leave a Comment