In the first days of our work as a Python programmer, we all encounter different types of bugs in our code, which after several painful hours in StackOverflow turn out to be not a bug, but features of Python. Below are 5 of the most common mistakes that most novice Python programmers make. Let's find out a little about them in order to save a few hours by asking questions on pages and in groups on Facebook.
1. Copy dictionaries or lists
When you need to make a copy of a dictionary or list, it is not enough just to use an assignment operator.
Wrong:>>> dict_a = {"name": "John", "address":"221B Baker street"} >>> dict_b = dict_a
Now, if you change or update dict_b, then dict_a will also be changed - all thanks to the assignment operator. Using this operator, you are trying to say that dict_b will point to the same object as dict_a.
')
>>> dict_b["age"] = 26 >>> dict_b {'address': '221B Baker street', 'name': 'John', 'age': 26} >>> dict_a {'address': '221B Baker street', 'name': 'John', 'age': 26} >>>
Correct: use copy () or deepcopy () methods.
>>> dict_c = dict_b.copy() >>> dict_c["location"] = "somewhere" >>> dict_c {'address': '221B Baker street', 'name': 'John', 'age': 26, 'location': 'somewhere'} >>> dict_b {'address': '221B Baker street', 'name': 'John', 'age': 26} >>> dict_a {'address': '221B Baker street', 'name': 'John', 'age': 26} >>>
See the difference between copy and deepcopy.2. Keys dictionaries
Let's try adding values to the dictionary:
>>> dict_a = dict() >>> dict_a {} >>> dict_a[1] = "apple" >>> dict_a[True] = "mango" >>> dict_a[2] = "melon"
If we try to display the dictionary on the screen, what will we see?
>>> dict_a {1: 'mango', 2: 'melon'}
What happened, where is the key true?
It must be remembered that the class Boolean is inherited from Integer (integers). And an integer equivalent to True is 1; the equivalent of False is 0. Hence, the value for key 1 is simply rewritten.
>>> isinstance(True, int) True >>> isinstance(False, int) True >>> True == 1 True >>> False == 0 True
3. Updating lists or dictionaries
Suppose you want to add an item to the list.
>>> list_a = [1,2,3,4,5] >>> list_a = list_a.append(6) >>> list_a >>>
Or trying to update the dictionary.
>>> dict_a = {"a" : "b"} >>> dict_a = dict_a.update({"c" : "d"}) >>> dict_a >>>
And now let's try to sort the list.
>>> list_b = [2,5,3,1,7] >>> list_b = list_b.sort() >>> list_b >>>
Why nothing is displayed, what are we doing wrong?
Most container methods (such as sort, update, append, add, etc.) are optimized for performance purposes — and avoid unnecessary creation of separate copies.
Do not attempt to assign the return value of such methods to a variable.
Right: >>> list_a = [1,2,3,4,5] >>> list_a.append(6) >>> dict_a = {"a" : "b"} >>> dict_a.update({"c" : "d"}) >>> dict_a {'c': 'd', 'a': 'b'} >>> list_a.sort() >>> list_a [1, 2, 3, 4, 5, 6]
4. Interned lines
In some cases, Python tries to reuse existing immutable objects. String interning is one such case.
>>> a = "gmail" >>> b = "gmail" >>> a is b True
Here we tried to create two different objects - strings. But when we checked them for equivalence, it turned out that they completely coincide. This is due to the fact that Python did not create another object b, but made b pointing to the first value of "gmail".
All strings of length 1 are interned. Lines that contain something other than ASCII characters, numbers, and the underscore character will not be interned.
Let's check.
>>> a = "@gmail" >>> b = "@gmail" >>> a is b False
You also need to remember that == is different from the is operator. The == operator checks whether the values are equivalent or not, whereas the is operator checks whether both variables refer to the same object.
>>> a = "@gmail" >>> b = "@gmail" >>> a is b False >>> a == b True
So keep this in mind when using immutable strings or the == and is operators.
5. Arguments by default are evaluated once.
Consider an example:
def func(a, lst=[]): lst.append(a) return lst print(func(1)) print(func(2))
What do you think will be displayed after two prints?
Let's run the code.
>>> def func(a, lst=[]): ... lst.append(a) ... return lst ... >>> print(func(1)) [1] >>> print(func(2)) [1, 2]
Why in the second case is displayed [1, 2]? Shouldn't it be just [2]?
So, the catch is that the arguments are calculated by default only once. When you first called the function - func (1) - the list was evaluated and realized that it was empty. So, you can add 1 to it. But in the second call, func (2), there is already one element in the list, so [1, 2] is displayed.
Bonus: Do not mix spaces and tabs. Just do not.