Mistakes easily made by ten Python programmers

Source: Internet
Author: User
People make mistakes whether they are studying or working. Although Python syntax is simple and flexible, there are also some pitfalls. If you are not careful, beginners and senior Python programmers may fall behind. This article shares 10 common errors. For more information, see Common error 1: The expression is incorrectly used as the default parameter of the function.

In Python, we can set a default value for a function parameter to make this parameter an optional parameter. Although this is a good language feature, when the default value is a variable type, it may also lead to some confusing situations. Let's take a look at the Python function definition below:

>>> Def foo (bar = []): # bar is an optional parameter. If the bar value is not provided, the default value is [],... bar. append ("baz") # But we will see a problem in this line of code later .... Return bar

A common mistake made by Python programmers is to assume that when a function is called, if no value is input for an optional parameter, this optional parameter is set to the specified default value. In the above Code, you may think that calling the foo () function repeatedly will always return 'baz', Because you default each foo () when the function is executed (the bar variable value is not specified), bar variables are set to [] (that is, a new empty list ).

However, the actual running result is as follows:

>>> foo()["baz"]>>> foo()["baz", "baz"]>>> foo()["baz", "baz", "baz"]

Strange, right? Why do I add the default value "baz" to the existing list every time I call the foo () function, instead of creating a new empty list?

The answer is that the default value of the optional parameter is only executed once in Python, that is, when the function is defined. Therefore, the bar parameter is initialized to the default value (that is, an empty list) only when the foo () function is defined, but every time the foo () function is called, will continue to use the list generated by the original initialization of the bar parameter.

Of course, a common solution is:

>>> def foo(bar=None):...  if bar is None:  # or if not bar:...    bar = []...  bar.append("baz")...  return bar...>>> foo()["baz"]>>> foo()["baz"]>>> foo()["baz"]

FAQ 2:Incorrect use of class variables

Let's take a look at the following example:

>>> class A(object):...   x = 1...>>> class B(A):...   pass...>>> class C(A):...   pass...>>> print A.x, B.x, C.x1 1 1

The result is normal.

>>> B.x = 2>>> print A.x, B.x, C.x1 2 1

Well, the results are the same as expected.

>>> A.x = 3>>> print A.x, B.x, C.x3 2 3

In Python, class variables are processed in a dictionary and follow the Method Resolution Order (MRO ). Therefore, in the code above, because class C does not have the attribute x, the interpreter will look for its base class (base class, although Python supports multiple inheritance, in this example, the base class of C is only ). In other words, C does not have its own x attributes independent of. Therefore, referencing C. x actually references A. x. If the relationship here is not properly handled, this problem occurs in the example.

Common error 3:The parameter of the exception block is incorrectly specified.

See the following code:

>>> try:...   l = ["a", "b"]...   int(l[2])... except ValueError, IndexError: # To catch both exceptions, right?...   pass...Traceback (most recent call last): File "
 
  "
 , line 3, in 
 
  IndexError: list index out of range
 

The problem with this Code is that the except T statement does not support specifying exceptions in this way. In Python 2.x, you need to use variable e to bind the exception to the optional second parameter to further view the exception. Therefore, in the above Code, the handle T statement does not capture the IndexError exception; instead, it binds the exception to a parameter named IndexError.

To correctly capture multiple exceptions in the T statement, you should specify the first parameter as a tuples and then write the exception types you want to capture in the tuples. In addition, to improve portability, use the as keyword. Both Python 2 and Python 3 support this usage.

>>> try:...   l = ["a", "b"]...   int(l[2])... except (ValueError, IndexError) as e: ...   pass...>>>

Common error 4:Incorrect understanding of variable name parsing in Python

The parsing of variable names in Python follows the so-called LEGB principle, that is, "L: local scope; E: local scope of def or lambda in the previous structure; G: global scope; B: built-in scope "(Local, Enclosing, Global, Builtin), search in order. Does it look simple? However, in fact, there are some special ways to apply this principle. Speaking of this, we have to mention the following common Python programming error. See the following code:

>>> x = 10>>> def foo():...   x += 1...   print x...>>> foo()Traceback (most recent call last): File "
 
  "
 , line 1, in 
 
   File "
  
   "
  , line 2, in fooUnboundLocalError: local variable 'x' referenced before assignment
 

What's wrong?

The above error occurs because when you assign a value to a variable in a certain scope, the variable is automatically regarded as a local variable in the scope by the Python interpreter, it will replace any variable with the same name in the previous scope.

It is because of this that a good code will appear at the beginning. After a value assignment statement is added to a function, UnboundLocalError occurs, which is no wonder to surprise many people.

When using the list, Python programmers are particularly prone to this trap.

See the following code example:

>>> Lst = [1, 2, 3] >>> def foo1 ():... lst. append (5) # No problem here...> foo1 () >>> lst [1, 2, 3, 5] >>> lst = [1, 2, 3] >>>> def foo2 ():... lst + = [5] #... but this is not true!... >>> Foo2 () Traceback (most recent call last): File"
 
  
"
 , Line 1, in
 
  
File"
  
   
"
  , Line 2, in fooUnboundLocalError: local variable 'lst' referenced before assignment
 

Er? Why does the function foo1 run normally while foo2 has an error?

The answer is the same as the previous example, but it is more difficult to understand. The foo1 function does not assign values to the lst variable, but foo2 does. We know that lst + = [5] is short for lst = lst + [5]. From this, we can see that the foo2 function is trying to assign a value to lst (therefore, it is considered by the Python interpreter as a variable in the local scope of the function ). However, the value we want to assign to the lst is based on the lst variable itself (which is also considered to be a variable in the local scope of the function), that is, the variable is not yet defined. This leads to an error.

Common error 5:Change the list when traversing the list

The following code may be very 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: Deleting item from a list while iterating over it...Traceback (most recent call last):   File "
 
  "
 , line 2, in 
 
  IndexError: list index out of range
 

Removing elements from a list or array is a concern of any experienced Python developer. However, although the above example is very obvious, Senior developers may make the same mistake unintentionally when writing more complex code.

Fortunately, the Python language integrates many elegant programming paradigms and can greatly simplify the Code if used properly. Another advantage of simplified code is that it is not easy to delete elements when traversing the list. One programming paradigm that can achieve this is the list analytical expression. In addition, the list analytical expression is particularly useful in avoiding this problem. The following uses the list analytical expression to re-implement the functions of the above Code:

>>> odd = lambda x : bool(x % 2)>>> numbers = [n for n in range(10)]>>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all>>> numbers[0, 2, 4, 6, 8]

Common Error 6:I don't understand how Python binds variables in closures.

See the following code:

>>> def create_multipliers():...   return [lambda x : i * x for i in range(5)]>>> for multiplier in create_multipliers():...   print multiplier(2)...

You may think the output result is as follows:

However, the actual output result is:

I was shocked!

This result is mainly because of the late binding mechanism in Python, that is, the value of the variable in the closure is only queried when the internal function is called. Therefore, in the above Code, every time the function returned by create_multipliers () is called, the value of variable I will be queried in a nearby scope (and by then, the loop has ended, therefore, variable I is finally assigned a value of 4 ).

To solve this common Python problem, you need to use some hack skills:

>>> def create_multipliers():...   return [lambda x, i=i : i * x for i in range(5)]...>>> for multiplier in create_multipliers():...   print multiplier(2)...02468

Please note! Here we use the default parameter to implement this lambda anonymous function. Some may think that this is very elegant, some may think it is very clever, and some may sneer. However, if you are a Python programmer, you should understand this solution anyway.

Common Errors 7:Circular dependencies between modules)

Assume that you have two files, a. py and B. py, which are referenced by each other, as shown below:

Code in the. py file:

Import bdef f (): return B. xprint f () B. py file code: import ax = 1def g (): print a. f ()

First, we try to import the. py module:

The code runs normally. Maybe this is beyond your expectation. After all, we have a circular reference problem here, so we should probably have a problem, isn't it?

The answer is that loop references alone will not cause problems. If a module has been referenced, Python does not reference it again. However, if the timing for each module to access functions or variables defined by other modules is incorrect, you may be in trouble.

Then return to our example, when we import. when the py module is used, it references B. the py module does not have any problems, because B. when the py module is referenced, it does not need to be accessed in. any variable or function defined in The py module. The unique reference to module a in Module B. py is to call the foo () function of module. However, the function call occurs in the g () function, but neither a. py nor B. py module calls the g () function. Therefore, no problem occurs.

However, if we try to import the B. py module (that is, we didn't reference the. py module before ):

>>> import bTraceback (most recent call last):   File "
 
  "
 , line 1, in 
 
     File "b.py", line 1, in 
  
     import a   File "a.py", line 6, in 
   
     print f()   File "a.py", line 4, in f return b.xAttributeError: 'module' object has no attribute 'x'
   
  
 

Bad. This is not a good situation! The problem here is that B is being imported. in the process of py, it tries to reference. py module, while. the py module then calls the foo () function again. The foo () function then tries to access B. x variable. However, the AttributeError error occurs only when the variable B. x is not defined.

To solve this problem, you can simply modify the B. py module and reference a. py in the g () function:

x = 1def g():  import a # This will be evaluated only when g() is called  print a.f()

If we import the B. py module again, there will be no problems:

>>> import b>>> b.g()1 # Printed a first time since module 'a' calls 'print f()' at the end1 # Printed a second time, this one is our call to 'g'

Common error 8:Module name conflicts with the Python standard library module name

A major advantage of the Python language is its own powerful standard library. However, because of this, if you do not pay attention to it, you may also get the same name for your module as the standard library module that comes with Python (for example, if there is a module in your code called email. in the Python standard library .)

This may cause you a difficult problem. For example, when importing module A, IF module A tries to reference Module B in the Python standard library, but you already have A module B with the same name, module A incorrectly references Module B in your code, rather than Module B in the Python standard library. This is also the cause of some serious errors.

Therefore, Python programmers should pay special attention to avoid using the same name as the Python standard library module. After all, it is much easier to modify the name of your module than to propose a PEP proposal to modify the name of the upstream module and make the proposal pass.

Common error 9:The difference between Python 2 and Python 3 cannot be solved.

Suppose there is the following code:

import sysdef bar(i):  if i == 1:    raise KeyError(1)  if i == 2:    raise ValueError(2)def bad():  e = None  try:    bar(int(sys.argv[1]))  except KeyError as e:    print('key error')  except ValueError as e:    print('value error')  print(e)bad()

If Python 2 is used, the code runs normally:

$ python foo.py 1key error1$ python foo.py 2value error2

But now we can switch to Python 3 and run it again:

$ python3 foo.py 1key errorTraceback (most recent call last): File "foo.py", line 19, in 
 
    bad() File "foo.py", line 17, in bad  print(e)UnboundLocalError: local variable 'e' referenced before assignment
 

What the hell is going on? The "problem" here is that in Python 3, the exception object cannot be accessed outside the scope of the T code block. (The reason for this design is that, if this is not the case, the reference loop of the stack frame will be retained until the Garbage Collector runs and clears the reference from the memory .)

One way to avoid this problem is to maintain a reference for the exception object outside the scope of the blocks T, so that the exception object can be accessed. The following code uses this method, so the output results in Python 2 and Python 3 are consistent:

import sysdef bar(i):  if i == 1:    raise KeyError(1)  if i == 2:    raise ValueError(2)def good():  exception = None  try:    bar(int(sys.argv[1]))  except KeyError as e:    exception = e    print('key error')  except ValueError as e:    exception = e    print('value error')  print(exception)good()

Run the code in Python 3:

$ python3 foo.py 1key error1$ python3 foo.py 2value error2

Great!

Common error 10:The del method is incorrectly used.

Suppose you have written the following code in the mod. py file:

Import fooclass Bar (object ):... def _ del _ (self): foo. cleanup (self. in the another_mod.py file, perform the following operations: import modmybar = mod. bar ()

If you run the another_mod.py module, AttributeError will occur.

Why? Because when the interpreter stops running, the global variables of this module are set to None. Therefore, in the preceding example, foo has been set to None before the _ del _ method is called.

To solve this tricky Python programming problem, use the atexit. register () method. In this way, after your program is executed (that is, when the program Exits normally), the specified handler will run before the interpreter is closed.

After applying the above method, the modified mod. py file may look like this:

import fooimport atexitdef cleanup(handle):  foo.cleanup(handle)class Bar(object):  def __init__(self):    ...    atexit.register(cleanup, self.myhandle)

This implementation allows you to call any necessary cleanup functions cleanly when the program ends normally. Obviously, the foo. cleanup function is used to determine how to handle the objects bound to self. myhandle.

Summary

Python is a powerful and flexible programming language. Many programming mechanisms and paradigms can greatly improve work efficiency. However, like any software tool or language, if you have limited or cannot appreciate the ability of the language, you may be blocked rather than benefited from it. As the saying goes, "you think you know enough, but it brings danger to yourself or others.

Constantly familiar with some of the nuances of the Python language, especially the 10 common errors mentioned in this Article, will help you effectively use this language, at the same time, it can also avoid making some common mistakes.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.