Table of contents
Python is a universally-used general & multi-purpose, high-level, interpreted, and object-oriented programming language. Today, we’re going to talk about the Common Mistakes of Python Programmers.
Python is beginner-friendly and is extremely simplistic, minimalistic, and easy-to-comprehend. Its pseudo-code nature is one of its most prominent powers that allows you to meditate on the solution to the problem and not just the language.
That’s why there is so much demand for Professional Python Web Development Company.
Moreover, Python lets you serve swiftly and incorporate systems more effectively.
While Python is acknowledged as a novice, favourable high-level language and remarkably superior, triumphant and extensively-adopted general-purpose programming language,
There are a lot of Common Mistakes that Python Programmers make. Let’s uncover the most common mistakes of Python development that businesses should also keep in mind when they hire python coders.
Faults in Python have a really distinct kind, called a traceback. You need to have an idea of each and every Python Mistakes to be able to become great at python.
When you skip a colon at the end of a line or incidentally add extra space when indenting under an if statement, or misremember a parenthesis, you will confront a syntax error.
This means that Python couldn’t comprehend your program.
To show a block of code in Python, each line of the block has to be betokened by the corresponding volume.
Unlike other languages, Python’s indentation indicates a lot more than simply making the code look neat. It is needed for symbolizing which block of code a statement belongs to. Several characteristics rely on indentation.
Few indentation errors are more difficult to spot in Python than others. For instance, tangling spaces and tabs can be challenging to locate in a code.
That’s where Noteworthy Python Application Performance Tips comes into the picture, without a doubt.!
In this case, whatever is observed in the editor may not be viewed by Python when the tabs are being computed as a representation of spaces.
Jupyter notebook supplants tabs with spaces automatically, but it throws an error in maximum cases. To bypass this for the entire block, all spaces or all tabs must be applied.
The init is a conserved program in python classes that are employed as constructors and termed so in object-oriented terminology. And it arrives when Python distributes memory to a new class object.
This process is summoned when an object is produced from a class and it permits the class to initialize the attributes of the class. It is one of the fatal Python Mistakes.
The objective is to anchor the values of instance members for the class object. Attempting to explicitly return a value from the init method signifies that the user aspires to diverge from its original mission.
In Python, class variables are privately managed as dictionaries and obey Method Resolution Order or MRO.
It signifies the class search path employed by Python to hunt for the correct technique to utilise in classes with multi-inheritance. This leads to a Python problem unless it’s worked correctly.
Python is prosperous with out-of-the-box library modules. A usual error is the usage of the identical name for modules in the Python standard library.
This directs to carrying different libraries which will attempt to import the module in the Python standard library and because of the module with the equal name, the other package will import the defined module, instead of the Python standard library module.
Python scope resolution is based on the LEGB rule or the Local, Enclosing, Global, Built-in rule. Python employs a unique strategy for scoping variables than other programming languages.
If a user creates an assignment to a variable in a range, that variable is automatically acknowledged by Python to be local to that scope and shadows any similarly called variable in an external scope.
Python enables one to determine that a function argument is arbitrary by giving a default value for it. While this is an excellent hallmark of the language, it can cause chaos when the default value is changeable. For example, consider this Python function definition:
>>> def foo(bar=): # bar is voluntary and defaults to  if not defined ... bar.append("baz") # but this line can be problematic ... return bar
A frequent confusion is to assume that the optional argument will be anchored to the designated default expression every point the function is declared without providing a value for the optional argument.
Let’s assume you have the below-furnished code:
>>> try: ... l = ["a", "b"] ... int(l) ... except ValueError, IndexError: # To catch both exceptions, right? ... pass ... Traceback (latest dialled last): File "<stdin>", line 3, in <module> IndexError: list index out of range
The issue here is that the except statement does not accept a list of exceptions described in this way.
Instead, in Python 2.x, the syntax except for Exception, is utilised to wrap the exception to the optional second parameter defined (in this event e), to make it accessible for additional investigation.
Hence, in the preceding code, the IndexError exception is not being picked by the except statement; instead, the exception ends up being bound to IndexError.
The conventional way to grab recurring exceptions in an except statement is to stipulate the first parameter as a tuple holding all exceptions to be hooked.
Also, for supreme portability, use the as a keyword, since that syntax is underpinned by both Python 2 and Python 3:
>>> try: ... l = ["a", "b"] ... int(l) ... except (ValueError, IndexError) as e: ... pass ... >>>
Python scope analysis is grounded on what is known as the LEGB rule or the Local, Enclosing, Global, Built-in rule.
However, it is not as straightforward as it seems. It is one of the most Common Mistakes in Python. But, you can avoid these mistakes, then Python is a great choice for startups.
There are some implications to the process that works in Python, which takes us to the more advanced Python programming query below. Analyze this:
>>> x = 10 >>> def foo(): ... x += 1 ... print x ... >>> foo() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in foo UnboundLocalError: local variable 'x' referenced before assignment
What’s the issue?
The preceding error happens when you perform an assignment to a variable in a scope, that variable is by default acknowledged by Python to be local to that scope and overlooks any identical termed variable in any external scope.
Many are thereby nabbed to get an UnboundLocalError in earlier working code when it is altered by superimposing an assignment statement around the body of a function.
It is especially common for it to confuse developers when utilizing lists. Consider the below-furnished example:
>>> lst = [1, 2, 3] >>> def foo1(): ... lst.append(5) # This goes well... ... >>> foo1() >>> lst [1, 2, 3, 5] >>> lst = [1, 2, 3] >>> def foo2(): ... lst +=  # ...Not this one! ... >>> foo2() Traceback (latest call list): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in foo UnboundLocalError: local variable 'lst' referenced assignment
Why did foo2 fail while foo1 worked well?
The answer is the same as the previous model query but is admittedly more illusive. foo1 is not performing an assignment to lst, while foo2 is memorising that lst +=  is really just short form for lst = lst + 
The issue with the below code looks obvious:
>>> odd = lambda x : bool(x % 2) >>> numbers = [n for n in range(10)] >>> for i in range(len(numbers)): ... if odd(numbers[i]): ... del numbers[i] # BAD: Removing item from a list while repeating over it ... Traceback (latest call last): File "<stdin>", line 2, in <module> IndexError: list index out of range
Removing an item from a table or array while repeating over it is a Python intricacy that is quite familiar to experienced python developers.
But, while the illustration above may be seemingly obvious, even superior developers can be incidentally struck by this in code as it is extremely complicated.
Luckily, Python includes a few sophisticated programming standards which when used correctly, can produce a remarkably clear and contoured code.
An added advantage here is that the more simplistic the code is, less prone it is to be attacked by the bug of unexpected deletion of a list item while emphasising over it.
Consider this example:
>>> def create_multipliers(): ... return [lambda x : i * x for i in range(5)] >>> for multiplier in create_multipliers(): ... print multiplier(2) ...
You might anticipate the subsequent output:
0 2 4 6 8
Nevertheless, you actually receive:
8 8 8 8 8
This occurs due to Python’s late-binding behavior which states that the values of variables employed in the closures are seen at the moment the internal function is declared. It is one of the most Common Mistakes in Python.
So, in the preceding code, whenever any of the returned functions are summoned, the value of it is surveyed in the neighboring scope at the point it is convened (and by the time the loop has finished, it has then been consigned to its final value of 4).
The solution to this Python problem is a kind of a trick-hack:
>>> def create_multipliers(): ... return [lambda x, i=i : i * x for i in range(5)] ... >>> for multiplier in create_multipliers(): ... print multiplier(2) ... 0 2 4 6 8
And there it is! We are endeavoring the power of default arguments here to create pseudonymous functions to accomplish the fancied behavior.
It may be sophisticated to some, while for others it is subtle. Some may also avoid it. But for a Python developer, it’s essential to understand this in any case.
Let’s assume you have two files, a.py and b.py, that imports each other, as follows:
In a.py: import b def f(): return b.x print f() In b.py: import a x = 1 def g(): print a.f()
First, let’s attempt importing a.py:
>>> import a 1
Operated accurately! Possibly that overwhelms you. After all, we have a circular import here which probably should be an issue.
The presence of a circular import is a dilemma in itself in Python. If a module is imported already, Python is clever enough to not re-import it.
Yet, depending on the position at which each module is venturing to reach functions or variables outlined in the other, running into problems seems obvious.
So, coming back to our model, where we imported a.py and it had no difficulty importing b.py, because b.py does not need anything from a.py to be determined at the time it is imported.
The only citation in b.py to a is the call to a.f(). But that call is in g() and nothing in a.py or b.py summons g().
However, what can happen if we try to import b.py (without having earlier imported a.py, that is):
>>> import b Traceback (latest call last): File "<stdin>", line 1, in <module> File "b.py", line 1, in <module> import a File "a.py", line 6, in <module> print f() File "a.py", line 4, in f return b.x AttributeError: 'module' object has no attribute 'x'
Well! There’s a problem! The method of importing b.py where it ventures to import a.py, which in return calls f() and tries to reach b.x is indeed a complicated problem. But b.x has not been defined yet. Hence, the AttributeError exception.
But, one solution at least to this is pretty minor. Simply alter b.py to import a.py in g():
x = 1 def g(): import a # This will be assessed only when g() is called print a.f() No, when we import it, everything seems perfect: >>> import b >>> b.g() 1 # Printed a first time since module 'a' calls 'print f()' at the end 1 # Printed a second time, this one is our call to 'g'
Consider the below file foo.py:
import sys def bar(i): if i == 1: raise KeyError(1) if i == 2: raise ValueError(2) def bad(): e = None try: bar(int(sys.argv)) except KeyError as e: print('key error') except ValueError as e: print('value error') print(e) bad() On Python 2, this works well: $ python foo.py 1 key error 1 $ python foo.py 2 value error 2
Now let’s turn it to Python 3:
$ python3 foo.py 1 key error Traceback (latest call last): File "foo.py", line 19, in <module> bad() File "foo.py", line 17, in bad print(e) UnboundLocalError: local variable 'e' referenced before assignment
What did just happen? The “problem” is that, in Python 3, the exception object is not available outside the scope of the except block.
The rationalisation for this is keeping a reference cycle with the stack frame in memory until the garbage collector operates and clarifies the references from memory.
This problem can be circumvented by keeping a reference to the exception object beyond the scope of the except block so that it remains available.
Here’s a version of the earlier example that employs this procedure, thereby bearing code that is both Python 2 and Python 3 favourable:
import sys def bar(i): if i == 1: raise KeyError(1) if i == 2: raise ValueError(2) def good(): exception = None try: bar(int(sys.argv)) except KeyError as e: exception = e print('key error') except ValueError as e: exception = e print('value error') print(exception) good() Running this on Py3k: $ python3 foo.py 1 key error 1 $ python3 foo.py 2 value error 2
Let’s suppose you had this in a file termed mod.py:
import foo class Bar(object): ... def __del__(self): foo.cleanup(self.myhandle)
And you attempted to do this from another_mod.py:
import mod mybar = mod.Bar()
Anticipate a bad AttributeError exception.
This is because the module’s global variables are all anchored to ‘None’ when the interpreter closes down. As a consequence, in the preceding instance, at the point that __del__ is called, the name foo has been set to None already.
A resolution to this relatively high-level Python programming dilemma would be to rather practice atexit.register(). In this way, when a program is done executing (when exiting ordinarily), the registered handlers are propelled before the interpreter is sealed down.
With this logic, a solution for the aforementioned mod.py code may resemble like this:
import foo import atexit def cleanup(handle): foo.cleanup(handle) class Bar(object): def __init__(self): ... atexit.register(cleanup, self.myhandle)
This implementation gives a neat and secure method of summoning any required cleanup functionality upon regular program termination.
Certainly, it’s up to foo.cleanup to judge what to do with the object adhered to the name self.myhandle, but now you know.
A very typical mistake that Python programmers often make is by substituting <is> for <equality> while relating integers. Since Python applies to cache integers, they may not be informed of this trip.
To understand this concept better, let’s take the below two examples for consideration.
In the first illustration, we’ve employed two variables classified as <sum> and <add>. And each of them banks the sum of two integers.
Next, we are equating the two variables with equality (==) operator. It will respond true as both the variables hold the same value.
We are experimenting with them utilising the identity (“is”) operator, but that also returns true. This is because Python has allotted identical address to both of them, which can be authenticated from their id values published at the edge.
But, a programmer who may not know how the two separate operations (“==” and “is”) can render the same outcome. And hence, commits the mistake without knowledge.
Python 2.7.10 (default, Jul 14 2015, 19:46:27) [GCC 4.8.2] on linux sum = 10 + 15 => None add = 5 + 20 => None sum == add => True sum => 25 add => 25 sum is add => True id(sum) => 25625528 id(add) => 25625528
However, it’s going to cost him in the following example.
In this case, long integers have been taken into consideration for use. The trick here is that Python only conceals integers between -5 to 256. Whereas the large numbers do seize their individual boxes to sleep.
Hence, while coordinating large integers with the identity (“is”) operator won’t return the corresponding result like the previous example.
300 + 200 is 500 => False 300 + 200 == 500 => True
Here is a list of a few anti-patterns that a Python programmer may use.
Use Of Java Style getter and setter Function
In Java, there is a massive use of getter/setter function to access the members of a class. But, such a scenario is considered as one of the most Common Mistakes Of Python Programmers.
An Example Of Anti-Pattern In Java
class Employee(object): def __init__(self, name, exp): self._name = name self._exp = exp # Java-style getter/setter def getName(self): return self._name def setName(self, name): self._name = name def getExp(self): return self._exp def setExp(self, exp): self._exp = exp emp = Employee('techbeamers', 10) print("Employee-1: ", emp.getName(), emp.getExp()) emp.setName('Python Programmer') emp.setExp(20) print("Employee-2: ", emp.getName(), emp.getExp())
How To Use This In Python?
class Employee(object): def __init__(self, name, exp): self.name = name self.exp = exp emp = Employee('techbeamers', 10) print("Default: ", emp.name, emp.exp) emp.name = 'Python Programmer' emp.exp = 20 print("Updated: ", emp.name, emp.exp)
Let’s take a list, add 9.
>>> foo()  >>> foo(numbers=[1,2]) [1, 2, 9] >>> foo(numbers=[1,2,3]) [1, 2, 3, 9] 1 2 3 4 5 6
And this happens when calling foo without numbers.
>>> foo() # first time, like before  >>> foo() # second time [9, 9] >>> foo() # third time... [9, 9, 9] >>> foo() # Whoa!! [9, 9, 9, 9] 1 2 3 4 5 6 7 8
In Python default values or functions are instantiated not when a specific function is called, but when it’s determined.
def foo(numbers=None): if numbers are None: numbers =  numbers.append(9) return numbers 1 2 3 4 5
Few other default values seem to work as presumed.
def foo(count=0): count += 1 return count 1 2 3 4 >>> foo() 1 >>> foo() 1 >>> foo(2) 3 >>> foo(3) 4 >>> foo() 1 1 2 3 4 5 6 7 8 9 10
The logic for this is not in the default value assignment but itself in the value. An integer is a changeless class. Doing count += 1 the actual value of count isn’t converting.
Attempt to name a function as the default value:
def get_now(now=time.time()): return now 1 2
As it is seen, while the value of time.time() is perpetual, it returns the same time.
>>> get_now() 1373121487.91 >>> get_now() 1373121487.91 >>> get_now() 1373121487.91 1 2 3 4 5 6
As a web app developer, if you’re not able to make the code easier, don’t make it harder for others as well. Develop a habit of writing comments and docstrings in your code. It will help you a lot.
def create_user(name, height=None, weight=None): '''Create a user entry in database. Returns database object created for user.''' # Logic to create entry into db and return db object
Always keep in mind, that a loop seldom counts the end number you define in a range. So, if you stipulate the range (1, 11), you truly get output for values between 1 and 10.
>>> a = list(range(1, 11)) >>> a [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> a 1 >>> a[0:5] [1, 2, 3, 4, 5] 1 2 3 4 5 6 71 2 36 7
If you are unable to get access to a value you anticipated, you need to review capitalization. Python is case sensitive, so MyVar is separate from myvar and MYVAR.
>>> MyVar = 1 >>> MYVAR Traceback (latest call last): File "< stdin >", line 1, in < module > NameError: name 'MYVAR' is not defined 1 2 3 4 5
Utilizing class variables inaccurately
>> class A(object): ... x = 1 ... >>> class B(A): ... pass ... >>> class C(A): ... pass ... >>> print A.x, B.x, C.x 1 1 1 1 2 3 4 5 6 7 8 9 10 11
The below example may make sense.
>> B.x = 2 >>> print A.x, B.x, C.x 1 2 1 1 2 3 And again. >>> A.x = 3 >>> print A.x, B.x, C.x 3 2 3 1 2 3
What made C.x change if we’ve only modified A.x.? This is because the class variables in Python have internal handling as dictionaries and obey the Method Resolution Order (MRO).
That’s why you will view trait x only in its base classes (only A in the earlier instance, even though Python encourages multiple inheritances) as there is no availability in class C.
Therefore, C doesn’t hold its individual x property, detached of A. And similarly, that sources to C.x are in fact references to A.x. This creates a Python problem unless you manage it correctly.
Python is an easy, efficacious and adaptable language with many mechanisms and models that can considerably enhance productivity.
However, there are a number of elements in Python that could go wrong, particularly for the new entrants to Python. But, by being careful and keeping the important points in mind, these errors can be bypassed pretty easily.
Best Python Applications and Examples have done that and that’s why they are so successful in the long run.
We hope you all had a great time reading this article and it will be a good help to any Python Developer in the near future. Thank You.!
Step into a new land of opportunities and unearth the benefits of digital transformation.