10 python programmers are prone to mistakes

Source: Internet
Author: User
Common Error 1: incorrectly use an expression as the default parameter for a function

In Python, we can set a default value for a parameter of a function so that it becomes an optional parameter. While this is a good language feature, it can also cause some confusing situations when the default value is a mutable type. Let's take a look at the following Python function definition:

>>> def foo (bar=[]):    # Bar is an optional parameter, if the value of bar is not provided, the default is [], ...  Bar.append ("Baz")  # but later we'll see a problem with this line of code. ...  Return bar

A common mistake that Python programmers make is to assume, of course, that the optional parameter is set to the specified default value each time the function is called, if no value is passed to the optional parameter. In the above code, you might think that calling the Foo () function repeatedly should always return ' Baz ', since you default every time the Foo () function executes (without specifying the value of the bar variable), the bar variable is set to [] (that is, a new empty list).

However, the actual operation results are as follows:

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

That's weird, isn't it? Why does the "Baz" default value be added to the existing list every time the Foo () function is called, instead of recreating a new empty list?

The answer is that the setting of the optional parameter default value will be executed only once in Python, that is, when defining the function. Therefore, the bar parameter is initialized to the default value (that is, an empty list) only when the Foo () function is defined, but then each time the Foo () function is called, it will continue to use the bar parameter to initialize the generated list.

A common solution, of course, is to:

>>> 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: to use class variables incorrectly

Let's 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 the Python language, class variables are processed in the form of a dictionary, and are followed by the method parsing order (methods Resolution Order,mro). Therefore, in the above code, because there is no X attribute in Class C, the interpreter will look for its base class (base class, although Python supports multiple inheritance, but in this case, the base class for C is only a). In other words, C does not have an X attribute that is independent of a and truly belongs to itself. So, referencing c.x is actually referencing a.x. If the relationship is not handled properly, this can lead to the problem in the example.

Common error 3: parameter that incorrectly specifies the exception code block (Exception block)

Take a look at the following code:

>>> Try:   ... L = ["A", "B"] ...   Int (l[2]) ... except ValueError, Indexerror: # To catch both exceptions, right?...   Pass ... Traceback (most recent): File "
 
  
   
  "
 
  , Line 3, in 
 
  
   
  indexerror:list index out of range
 
  

The problem with this code is that the except statement does not support specifying exceptions in this manner. In Python 2.x, you need to use the variable E to bind an exception to the second optional parameter in order to see the exception further. Therefore, in the preceding code, the except statement does not catch the Indexerror exception, but instead binds the exception that appears to a parameter named Indexerror.

To correctly capture multiple exceptions in a except statement, specify the first parameter as a tuple, and then write down the type of exception you want to capture in the tuple. In addition, to improve portability, use the AS keyword, which is supported by Python 2 and Python 3.

>>> Try:   ... L = ["A", "B"] ...   Int (l[2]) ... except (ValueError, Indexerror) as E:   ... Pass...>>>

Common error 4: Error Understanding variable name resolution in Python

Variable name resolution in Python follows the so-called LEGB principle, "L: local scope; E: The local scope of def or lambda in the previous layer structure; G: global scope; B: Built-in scope" (Local,enclosing,global,builtin) , which are searched sequentially. Does it look simple? In fact, however, there are some special ways in which this principle comes into force. Speaking of this, we have to mention the following common Python programming error. Take a look at the following code:

>>> x = 10>>> def foo (): ...   x + = 1   ... Print x...>>> foo () Traceback (most recent call last): File "
 
  
   
  "
 
  , Line 1, in 
 
  
   
   F Ile "
  
   
    
   "
  
   , Line 2, in foounboundlocalerror:local variable ' x ' referenced before assignment
   
  

What's the problem?

The above error occurs because when you assign a value to a variable within a scope, the variable is automatically treated as a local variable of that scope by the Python interpreter and supersedes any variable of the same name in the previous level scope.

It is precisely because of this, the first good code will appear, after a function to add an assignment statement has been unboundlocalerror, it is no wonder that many people surprised.

Python programmers are particularly vulnerable to this trap when using lists.

Take a look at the following code example:

>>> LST = [1, 2, 3]>>> def foo1 ():   ... Lst.append (5)  # There's no problem here. ...>>> foo1 () >>> lst[1, 2, 3, 5]>>> lst = [1, 2, 3]>>> def fo O2 ():   ... LST + = [5]   # ... But it's not going to be right here.!... >>> Foo2 () Traceback (most recent): File "
 
  
   
  "
 
  , line 1, 
 
  
    C10/>file "
  
   
    
   "
  
   , Line 2, in foounboundlocalerror:local variable ' LST ' referenced before assign ment
 
  

Uh? Why does the function foo1 run normally, Foo2 has an error?

The answer is the same as the previous example, but it's even harder to fathom. The FOO1 function does not assign a value to the LST variable, but Foo2 has an assignment. We know that LST + = [5] is just a shorthand for LST = LST + [5], from which we can see that the Foo2 function is trying to assign a value to LST (hence, the variable that the Python interpreter considers to be a function-local scope). However, the value we want to assign to LST is based on the LST variable itself (at this point, it is also considered a variable within the local scope of the function), i.e. the variable is not yet defined. There was a mistake.

Common error 5: to change a list while traversing a list

The problem with this code should be pretty obvious:

>>> odd = lambda x:bool (x% 2) >>> numbers = [n for n in range]]>>> for I in range (Len (numb ers)): ...   If Odd (Numbers[i]): ...     del Numbers[i] # bad:deleting item from a list while iterating over it ... Traceback (most recent):   File "
 
  
   
  "
 
  , Line 2, in 
 
  
   
  indexerror:list index ou T of range
 
  

Removing elements while traversing a list or array is an issue that any experienced Python developer would be aware of. But while the example above is obvious, senior developers are likely to inadvertently make the same mistake when writing more complex code.

Fortunately, the Python language incorporates a number of elegant programming paradigms that, if used properly, can greatly simplify the code. One benefit of simplifying code is that it is not easy to delete an element when traversing a list. A programming paradigm that can do this is the list-parsing. Moreover, list parsing is particularly useful in avoiding this problem, and the following code is re-implemented with a list-parsing function:

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

Common error 6: do not understand how Python binds variables in closures

Take a look at 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 might think the output should look like this:

However, the actual output results are:

It's a shock!

This result arises mainly because of the late binding (late binding) mechanism in Python, where the value of a variable in a closure is queried only when an intrinsic function is called. Therefore, in the above code, each time the function returned by Create_multipliers () is called, the value of the variable i is queried in a nearby scope (and at that time, the loop has ended, so the variable i is finally given a value of 4).

To solve this common python problem, you need to use some hack techniques:

>>> 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 parameters to implement this lambda anonymous function. Some may think it is graceful, some will find it ingenious, and others will scoff. However, if you are a Python programmer, you should be aware of this workaround anyway.

Common error 7: cyclic dependencies between modules (circular dependencies)

Let's say you have two files, a.py and b.py, each referencing each other as follows:

Code in the a.py file:

Import Bdef F ():  return b.xprint F () b.py file in code: Import ax = 1def g ():  print A.F ()

First, we try to import the a.py module:

The code runs fine. Perhaps this is beyond your expectation. After all, we have a circular reference to this problem here, presumably it should be a problem, isn't there?

The answer is that the mere existence of circular references does not in itself cause problems. If a module is already referenced, Python can do so without referencing it again. But if every module tries to access functions or variables defined by other modules, you are likely to get into trouble.

So back to our example, when we import the a.py module, it does not have a problem referencing the b.py module, because the b.py module does not need to access any variables or functions defined in the a.py module when it is referenced. The only reference to the A module in the b.py module is the foo () function that calls the A module. But that function call occurs in the G () function, and the G () function is not called in the a.py or b.py module. Therefore, the problem does not occur.

However, if we try to import the b.py module (i.e. without previously referencing the a.py module):

>>> Import Btraceback (most recent call last):   File "
 
  
   
  "
 
  , Line 1, in 
 
  
   
     File "b.py", line 1, with 
  
   
    
     import a   File "a.py", line 6, in 
   
    
     
     print f ()   File "a.py", Li NE 4, in F return b.xattributeerror: ' Module ' object have no attribute ' x '
   
    
  
   
 
  

Bad. The situation is not very good! The problem here is that in the process of importing b.py, it tries to reference the a.py module, and the a.py module then calls the Foo () function, which then attempts to access the b.x variable. But this time, the b.x variable has not been defined, so there is a Attributeerror exception.

A very simple way to solve this problem is to simply modify the next b.py module to refer to a.py within the G () function:

x = 1def g ():  Import a # This would be evaluated only when G () is called  print A.F ()

Now that we import the b.py module again, there will be no problem:

>>> import b>>> B.G () 1 # Printed a first time since module ' a ' calls ' Print f () ' At the End1 # printed a Second time, this one was our call to ' G '

Common error 8: module naming conflicts with Python standard library module names

One of the great advantages of the Python language is its own powerful standard library. However, because of this, if you do not deliberately pay attention to, you can also have a module for their own and Python with the standard library module of the same name (for example, if you have a module in your code called email.py, then this will be in the Python standard library with the same name of the module conflict. )

This is likely to bring you a difficult problem. For example, when importing module A, if the module a tries to reference module B in the Python standard library, but because you already have a module B with the same name, module a incorrectly references module B in your own code, not module B in the Python standard library. This is also the cause of some serious errors.

Therefore, Python programmers should be careful 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 suggest a pep proposal to modify the name of the upstream module and let the proposal pass.

Common Error 9: failed to resolve the difference between Python 2 and Python 3

Suppose you have 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 it is Python 2, then the code works fine:

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

But now, let's switch to Python 3 and run it again:

$ python3 foo.py 1key Errortraceback (most recent call last): File "foo.py", line at Bad 
 
  
   
    () file "FOO.P Y ", line x, in Bad  print (e) unboundlocalerror:local variable ' e ' referenced before assignment
 
  

What the hell is going on here? The "problem" here is that in Python 3, the exception object is inaccessible outside the scope of the except code block. (The reason for this is that if this is not the case, the stack frame retains its reference loop until the garbage collector runs and the reference is purged from memory.) )

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

Import Sysdef Bar (i):  if i = = 1:    raise Keyerror (1)  if i = = 2:    raise ValueError (2) def good ():  exceptio n = 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 under Python 3:

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

That's great!

Common Mistakes: error using the Del method

Let's say you wrote the following code in the mod.py file:

Import Fooclass Bar (object):    ...  def __del__ (self):    foo.cleanup (Self.myhandle), you do the following in the another_mod.py file: import modmybar = mod. Bar ()

If you run the another_mod.py module, a Attributeerror exception will occur.

Why? Because when the interpreter finishes running, the module's global variables are set to none. Therefore, in the example above, when the __del__ method is called, Foo has been set to none.

One way to solve this somewhat tricky Python programming problem is to use the Atexit.register () method. In this case, when your program executes (that is, if you exit the program normally), the handler you specify will run before the interpreter is closed.

With this method applied, the modified mod.py file may be:

Import fooimport atexitdef Cleanup (handle):  foo.cleanup (Handle) class Bar (object):  def __init__ (self):    ...    Atexit.register (cleanup, self.myhandle)

This implementation supports cleanly invoking any necessary cleanup functions when the program terminates gracefully. Obviously, the above example will be determined by the Foo.cleanup function to handle the object that Self.myhandle binds to.

Review

Python is a powerful and flexible programming language that provides many programming mechanisms and paradigms that can greatly improve productivity. However, as with any software tool or language, if the ability to understand the language is limited or not appreciated, then sometimes you will be hindered rather than benefited. As one proverb says, "You think you know enough, but in reality it poses a danger to yourself or others."

Getting familiar with some of the nuances of the Python language, especially the 10 most common mistakes mentioned in this article, will help you use the language effectively, while avoiding some of the more common mistakes you can make.

  • 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.