Programmers older drivers have the wrong Python traps and defects list

My personal definition of the trap is this: code looks can work, but not to "assume", "the way you directly if a piece of code error, an exception is thrown, I do not think this is a trap for example, Python programmers. You should have encountered the "UnboundLocalError", example:

a=1
def func():
... a+=1
... print a
...
func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in func
UnboundLocalError: local variable 'a' referenced before assignment

For "UnboundLocalError", as well as more advanced version:

import random

def func(ok):
if ok:
a = random.random()
else:
import random
a = random.randint(1, 10)
return a

func(True)# UnboundLocalError: local variable 'random' referenced before assignment

Possible for many python novice, this Error confusing. But I think this is not a trap, because this code will be given, instead of silently running in the wrong way. True villain is not afraid, afraid of hypocrites. I think defect like a hypocrite.

So in Python what really claim to be a trap?

The first: to mutable objects as default values

This estimate is the most widely known of, Python and many other languages, provides default parameters, the default parameter is indeed a good thing, allowing the function caller to ignore some of the details (such as GUI programming, Tkinter, QT), for lambda expressions also very useful. But if you use mutable objects as default values, so the thing is not so pleasant.

def f(lst = []):
... lst.append(1)
... return lst
...
f()
[1]
f()
[1, 1]

Not surprise surprise? ! The reason, python everything is an object, the function is no exception, the default parameter is only a function of the property. The default parameters when the function has been defined in the evaluation.

  Default parameter values are evaluated when the function definition is executed.

There is a more appropriate upper stackoverflow example to illustrate default parameters are evaluated at the time defined, instead of calling time. 

import time
def report(when=time.time()):
... return when
...
report()
1500113234.487932
report()
1500113234.487932

python docoment gives a standard solution:

  A way around this is to use None as the default, and explicitly test for it in the body of the function

def report(when=None):
... if when is None:
... when = time.time()
... return when
...
report()
1500113446.746997
report()
1500113448.552873

第二: x += y vs x = x + y

Generally speaking, the two are equivalent, it appears to be at least equivalent (which is the definition of a trap - looks OK, but not necessarily correct).

x=1;x += 1;print x
2
x=1;x = x+1;print x
2
x=[1];x+=[2];print x
[1, 2]
x=[1];x=x+[2];print x
[1, 2]

Uh, he was hit the face of the speed of light?

x=[1];print id(x);x=x+[2];print id(x)
4357132800
4357132728
x=[1];print id(x);x+=[2];print id(x)
4357132800
4357132800

The former point to a new object x, in which x is to modify the original object, of course, that the effect is dependent on the correct application scenario. At least, you must know, sometimes the two are not the same

Third, the magic of parentheses - ()

Parentheses (parenthese) in a variety of programming languages ​​have a wide range of applications, python in parentheses also represents a tuple (tuple) of this type of data, tuples are immutable sequence.

a = (1, 2)
type(a)
<type 'tuple'>
type(())
<type 'tuple'>

But if it is only one element

a=(1)
type(a)
<type 'int'>

Magic is not magic, if there is only one element tuple, the correct posture is:

a=(1,)
type(a)
<type 'tuple'>

Fourth: Generate a list of elements is a list of

This is a bit like a two-dimensional array, of course, to generate a list of dictionary elements are also possible, more popular that generates a sequence element is a variable object

Very simple thing:

a= [[]] * 10
a
[[], [], [], [], [], [], [], [], [], []]
a[0].append(10)
a[0]
[10]

It looks good, plain and simple, but

a[1]
[10]
a
[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]

I guess it should not be the result you expected it, reason, or because the python in the list is a variable object with a variable object above wording everyone points to, correct posture

a = [[] for _ in xrange(10)]
a[0].append(10)
a
[[10], [], [], [], [], [], [], [], [], []]

Fifth, when the access list, the list of modifications

List (list) is widely used in python, of course, often add or remove some elements when accessing the list. For example, the following function, try to delete elements of a multiple of 3 in the list are:

def modify_lst(lst):
... for idx, elem in enumerate(lst):
... if elem % 3 == 0:
... del lst[idx]

have a test,

lst = [1,2,3,4,5,6]
modify_lst(lst)
lst
[1, 2, 4, 5]

As if nothing was wrong, but that's just good luck

lst = [1,2,3,6,5,4]
modify_lst(lst)
lst
[1, 2, 6, 5, 4]

In the above example, the element 6 will not be deleted. If modify_lst function print idx, item may find clues: lst in shorter, but the idx is incremented, so the error in the above example, it is removed after 3, 6 became the first two elements of the lst ( starting from 0). In C ++, if the time to traverse the container to remove elements with an iterator will have the same problem.

If the logic is simple, using a list comprehension is a good idea

Sixth, closures and lambda

This is also an example of the older students long talk in other languages ​​have a similar situation. Look at an example:

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

create_multipliers a list if the return value of each element of the list is a function of - the input parameter x i multiplied by a multiple of a function. It is expected that the results of 0,2,4,6,8. But the result is 5 8, not unexpected accident.

Since the emergence of this trap, he often used the lambda, it may be considered a problem lambda, but lambda expressed reluctance to back the pot. Nature of the problem and find the python attribute rules, LEGB (local, enclousing, global, bulitin), in the example above, i is the closure is in the scope (enclousing), and Python closure is late binding, this means that the value of closure used variables in the internal function is called from the query.

The solution is very simple, that is, change the scope to local scope closures.

def create_multipliers():
... return [lambda x, i = i:i*x for i in range(5)]
...

Seventh, the definition of del

, C ++, construction, concept most computer science students are likely to learn first C destructor should be very familiar. Thus, when the switching to the python, naturally wonder if there is a corresponding function. For example, in C ++ very famous RAII, i.e. to manage resources (such as memory, file descriptors) by constructing a periodic statement destructor. That in python to achieve the same effect how to do it, the need to find an object function when the destruction will be called, so found the init , del function, may simply write two examples can be found really work. But in fact may fall into a trap, in python documnet is described:

  Circular references which are garbage are detected when the option cycle detector is enabled (it’s on by default), but can only be cleaned up if there are no Python-level del() methods involved.

In simple terms, if the object in a circular reference defines del , then the python gc can not be recovered, therefore, there is a risk of memory leaks

Eighth, different postures import the same module

Example stackoverflow minor modifications in the example, suppose we have a package called mypackage, which contains three files python: mymodule.py, the main.py, the init .py. mymodule.py code is as follows:

l = []
class A(object):
pass

main.py code is as follows:

def add(x):
from mypackage import mymodule
mymodule.l.append(x)
print "updated list",mymodule.l, id(mymodule)

def get():
import mymodule
print 'module in get', id(mymodule)
return mymodule.l

if name == 'main':
import sys
sys.path.append('../')
add(1)

ret = get()
print "lets check", ret

Run python main.py, results are as follows:

updated list [1] 4406700752
module in get 4406700920
lets check []

As can be seen operating results, import the function in the add and get mymodule not the same module, different ID. Of course, in python2.7.10 in line 13 main.py need of such an effect can occur. You may ask, who will write the line 13 this code? In fact, in many projects, in order to facilitate import time will be added to sys.path pile path. Then in the project, we agree with the latter way is very necessary to import the

Ninth, python upgrade

python3.x not backwards compatible, so if you upgrade from 2.x to 3.x time have to be careful, here are two:

In python2.7, the range of the return value is a list; in python3.x, the return of a target range.

map (), filter (), dict.items () returns the list python2.7, iterator returned in 3.x. Of course most of them are good choices iterator, more pythonic, but also has the disadvantage that can only be traversed once. Instagram sharing in, also referred to as a pit father of this bug caused.

Tenth, gil

Ending GIL, because gil is a well-recognized defects in Python!

Come from other language students may see a python threading module, to take over with, and found that the effect does not, ah, then it will spray, what the hell.

to sum up:

There is no doubt say, python is very easy to use and very powerful one language. python very flexible and can be customized very strong. At the same time, there are some traps, these traps can figure out a better grasp, the use of such language. This article lists some python some flaws, this is a non-exhaustive list, welcome to add.

Source Author: xybaby
Source Link: www.cnblogs.com/xybaby/p/7183854.html

Reproduced in: https: //blog.51cto.com/10515215/2405326

Guess you like

Origin blog.csdn.net/weixin_34346099/article/details/91656106