Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the ten most common mistakes made by Python programmers

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article is to share with you what are the ten most common mistakes made by Python programmers. I think it is very practical, so I share it with you. I hope you can get something after reading this article.

Common error 1: mistakenly using an expression as the default parameter of a function

In Python, we can set a default value for a parameter of the function, making it optional. Although this is a good language feature, it can also lead to 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 optional. If no value of bar is provided, it defaults to [],... Bar.append ("baz") # but we'll see something wrong with this line of code later. ... Return bar

A common mistake made by Python programmers is to take it for granted that every time a function is called, if no value is passed for the optional parameter, the optional parameter will be set to the specified default value. In the above code, you may feel that repeated calls to the foo () function should always return 'baz', because you default that 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 running result is as follows:

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

Isn't that weird? Why is it that every time the foo () function is called, the default value of "baz" is added to the existing list instead of recreating a new empty list?

The answer is that the setting of the default value of the optional parameter is only executed once in Python, 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 then each time the foo () function is called, it continues to initialize the generated list with 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: misusing class variables

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.x 1 1 1

The result is normal.

> B.X = 2 > print A.x, B.x, C.x 1 21

Well, the result is as expected.

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

In the Python language, class variables are processed as dictionaries and follow the method parsing order (Method Resolution Order,MRO). Therefore, in the above code, since there is no attribute x in class C, the interpreter will look for its base class (base class, although Python supports multiple inheritance, in this case, the base class of C is only A). In other words, C does not have its own x attribute independent of A. So, citing C.x is actually referring to A.x. If the relationship here is not handled properly, it will lead to the problem in the example.

Common error 3: incorrectly specify the parameters of 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 call last): 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 way. In Python 2.x, you need to use the variable e to bind the exception to the optional second parameter to see the exception further. Therefore, in the above code, the except statement does not catch an IndexError exception; instead, it binds the exception that occurs to a parameter named IndexError.

To catch multiple exceptions correctly in an except statement, specify * parameters as tuples, and then write down the type of exception you want to catch in the tuple. In addition, to improve portability, use the as keyword, which is supported by both Python 2 and Python 3.

Try:... L = ["a", "b"]. Int (l [2]). Except (ValueError, IndexError) as e:... Pass... > >

Common error 4: misunderstanding the parsing of variable names in Python

The resolution 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 upper structure; G: global scope; B: built-in scope" (Local,Enclosing,Global,Builtin), looking up sequentially. Doesn't it look easy? However, in fact, there is something special about the way this principle takes effect. Speaking of which, 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 File "", line 2, in foo UnboundLocalError: local variable'x 'referenced before assignment

What's wrong?

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

It is because of this that there is good code at the beginning, and then UnboundLocalError appears after adding an assignment statement inside a function, which is no wonder it surprises many people.

Python programmers are particularly likely to fall into this trap when using lists.

Take a look at 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] #... Foo2 () Traceback (most recent call last): File ", line 1, in File", line 2, in foo UnboundLocalError: local variable 'lst' referenced before assignment

Huh? Why does the function foo1 work properly, but foo2 has an error?

The answer is the same as the previous example, but more elusive. The foo1 function does not assign a value to the lst variable, but foo2 does. We know that lst + = [5] is just an acronym for lst = lst + [5], from which we can see that the foo2 function is trying to assign a value to lst (therefore, it is considered by the Python interpreter to be a variable in the local scope of the function). However, the value we want to assign to lst is based on the lst variable itself (at this time, it is also considered to be a variable in the local scope of the function), which means that the variable has not yet been defined. That's why there was a mistake.

Common error 5: change the list when traversing the list

The problem with the following code should be 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 while traversing is an issue that any experienced Python developer will notice. But although the above example is obvious, senior developers are likely to inadvertently make the same mistake when writing more complex code.

Fortunately, the Python language incorporates many elegant programming paradigms, and if used properly, the code can be greatly simplified. Another benefit of simplifying the code is that it is not easy to delete elements when traversing the list. One programming paradigm that can do this is list parsing. Moreover, list parsers are particularly useful in avoiding this problem, so let's reimplement the functionality of the above code with list parsers:

> 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: 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:

0

two

four

six

eight

However, the actual output is:

eight

eight

eight

eight

eight

What a surprise!

This result is mainly due to the late binding (late binding) mechanism in Python, that is, the values of variables in the closure are queried only when the internal 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 the nearby scope (and by that time, the loop is over, so the variable inotify * is assigned a value of 4).

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

> def create_multipliers (): Return [lambda x, iTuni: I * x for i in range (5)]... > for multiplier in create_multipliers (): Print multiplier (2)... 0 2 4 6 8

Attention please! Here we use the default parameters to implement the lambda anonymous function. Some people may think it's elegant, some will think it's clever, and others will scoff. However, if you are a Python programmer, you should be aware of this solution anyway.

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

Suppose you have two files, a.py and b.py, which refer to each other, as follows:

The code in the a.py file:

Import b def f (): return b.x print f ()

The code in the b.py file:

Import a x = 1 def g (): print a.f ()

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

> import a

one

The code works fine. Maybe it's not what you expected. After all, we have the problem of circular reference here, which must be a problem, isn't it?

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

So back to our example, when we import the a.py module, it has no 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 block when it is referenced. The only reference to module an in the b.py module is the call to module a's foo () function. But that function call occurs in the g () function, and the g () function is not called in either the a.py or b.py module. Therefore, there will be no problems.

However, what if we try to import the b.py module (that is, without referring to the a.py module before):

> import b Traceback (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.x AttributeError: 'module' object has no attribute' x'

Oh, no. It's not good! The problem here is that during the import of b.py, it attempts to reference the a.py module, which in turn calls the foo () function, which in turn attempts to access the b.x variable. But at this point, the b. X variable has not yet been defined, so the AttributeError exception occurs.

A very simple way to solve this problem is to simply modify the b.py module to reference a.py inside the g () function:

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

Now if we import the b.py module, there won't be any problems:

> 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'

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

One of the great advantages of the Python language is its own powerful standard library. However, because of this, if you don't pay attention to it, you may also give your module the same name as the module that comes with the Python standard library (for example, if you have a module in your code called email.py, then this will conflict with the module with the same name in the Python standard library. )

This is likely to bring you difficult problems. For example, when importing module A, if 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 will mistakenly reference module B in your own code instead of module B in the Python standard library. This is also the cause of some serious mistakes.

Therefore, Python programmers should be extra careful not to use the same name as the Python standard library module. After all, it's much easier to change the name of your own module than to propose a PEP proposal to change the name of the upstream module and let it pass.

Common error 9: failed to resolve differences between Python 2 and Python 3

Suppose you have the following code:

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 [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 1 key error 1$ python foo.py 2 value error 2

But now, let's run it again with Python 3:

$python3 foo.py 1 key error Traceback (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 on earth is going on? The "problem" here is that in Python 3, exception objects are inaccessible outside the scope of the except code block. The reason for this design is that if not, its reference loop will remain in the stack frame until the garbage collector runs and clears the reference from memory. )

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

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 [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 1 key error 1 $python3 foo.py 2 value error 2

great!

Common error 10: incorrect use of del method

Suppose you wrote the following code in the mod.py file:

Import foo class Bar (object):... Def _ del__ (self): foo.cleanup (self.myhandle)

After that, you do the following in the another_mod.py file:

Import mod mybar = mod.Bar ()

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

Why? Because when the interpreter finishes running, the global variable of the module will be set to None. Therefore, in the above example, foo is set to None before the _ _ del__ method is called.

One way to solve this somewhat tricky Python programming problem is to use the atexit.register () method. In this way, when the execution of your program is complete (that is, when you exit the program normally), the handler you specify will run before the interpreter closes.

With the above method applied, the modified mod.py file might look 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 allows you to neatly invoke any necessary cleanup functions when the program terminates normally. Obviously, in the above example, it is up to the foo.cleanup function to decide what to do with the objects bound by self.myhandle.

Python is a powerful and flexible programming language, which provides many programming mechanisms and paradigms that can greatly improve work efficiency. But like any software tool or language, if the ability to understand the language is limited or unappreciated, then sometimes you will be hindered rather than benefited. As a proverb goes, "you think you know enough, but it brings danger to yourself or others" (knowing enough to be dangerous).

These are the ten most common mistakes made by Python programmers. The editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report