My personal definition of traps is this: the code seems to work, but not in the way you "take it for granted". If a piece of code goes wrong and throws an exception, I don't think it's a trap. For example, Python programmers 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 "<st Din> ", line 2, in funcunboundlocalerror:local variable ' a ' referenced before assignment
For "Unboundlocalerror", there is a more advanced version:
Import Random def func (OK): if ok:a = Random.random () else:import Random a = Random.randint (1 , ten) return a Func (True) # unboundlocalerror:local variable ' random ' referenced before assignment
Perhaps for many novice python, this error is confusing. But I think this is not a trap, because this code will be error, rather than silently run in the wrong way. Not afraid of the real villain, it is afraid of pseudo-gentleman. I think the flaw is like a hypocrite.
So what are the real pitfalls of python?
First: Use the Mutable object as the default parameter
This estimate is the most widely known, and Python, like many other languages, provides default parameters, and the default parameter is really a good thing, allowing the function caller to ignore some details (such as GUI programming, TKINTER,QT), which is also useful for lambda expressions. But if you use mutable objects as default parameters, things are less enjoyable.
>>> def f (lst = []): ... lst.append (1) ... return lst...>>> f () [1]>>> f () [1, 1]
Surprise not surprise?! The reason is that everything in Python is an object, and the function is not listed, and the default parameter is just a property of the function. The default parameters are evaluated when the function is defined.
Default parameter values is evaluated when the function definition is executed.
There is a more appropriate example on StackOverflow to show that the default parameter is evaluated at the time of definition, not when it is called.
>>> Import time>>> def report (When=time.time ()): ... return when...>>> report () 1500113234.487932>>> report (1500113234.487932)
The Python docoment gives the standard solution:
A-the-to-use-around-A-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 () 1500 113446.746997>>> report (1500113448.552873)
Second: x + = y vs x = x + y
In general, the two are equivalent and at least appear to be equivalent (which is also the definition of a trap-looks OK, but not necessarily correct).
>>> x=1;x + = 1;print x2 >>> x=1;x = x+1;print x2>>> x=[1];x+=[2];p rint x[1, 2]>>> x=[1 ];X=X+[2];p rint x[1, 2]
Uh, hit the face with the speed of light?
>>> x=[1];p rint ID (x); x=x+[2];p rint ID (x) 43571328004357132728>>> x=[1];p rint ID (x); x+=[2];p rint ID (x) 43571328004357132800
The former X points to a new object, the latter x in the original object is modified, of course, that effect is correct depending on the application scenario. At least, you know, sometimes they're not the same.
Third, the magical parenthesis – ()
Parentheses (Parenthese) are widely used in a variety of programming languages, and in Python, parentheses can also represent a tuple (tuple) data type, which is a sequence of immutable.
>>> a = (1, 2) >>> type (a) <type ' tuple ' >>>> type (()) <type ' tuple ' >
But what if there's only one element?
>>> a= (1) >>> type (a) <type ' int ' >
Magic is not magical, if you want to represent a tuple with only one element, the correct posture is:
>>> a= (1,) >>> type (a) <type ' tuple ' >
IV: Generating an element is a list of lists
This is a bit like a two-dimensional array, of course, generating an element is a list of dictionaries is also possible, more generally speaking, the generation of an element is a variable object sequence
Very simple:
>>> a= [[]] * 10>>> a[[], [], [], [], [], [], [], [], [], []]>>> A[0].append (Ten) >>> a[ 0] [10]
It looks good, simple and clear, but
>>> a[1][10]>>> a[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]
I guess this is not what you expected it to be, the reason, or because the list in Python is a mutable object, the above notation everyone points to the same variable object, the correct posture
>>> a = [[] for _ in Xrange (Ten)]>>> A[0].append (Ten) >>> a[[10], [], [], [], [], [], [], [], [], []]
At the time of accessing the list, modify the list
Lists (list) are widely used in Python, and of course often add or remove elements when accessing a list. For example, the following function attempts to delete an element that is a multiple of 3 in the list:
>>> def modify_lst (LST): ... for IDX, elem in Enumerate (LST): ... if elem% 3 = = 0: ... del lst[idx]
Test it, please.
>>> lst = [1,2,3,4,5,6]>>> modify_lst (LST) >>> lst[1, 2, 4, 5]
There seems to be nothing wrong, but it's just luck.
>>> lst = [1,2,3,6,5,4]>>> modify_lst (LST) >>> lst[1, 2, 6, 5, 4]
In the above example, 6 of this element is not deleted. If you print idx in the MODIFY_LST function, item can find the clue: LST is getting shorter, but the IDX is incremented, so in the example above, when 3 is deleted, 6 becomes the 2nd element of LST (starting with 0). In C + +, the same problem can occur if you use an iterator to delete an element while traversing the container.
If logic is simple, using list comprehension is a good idea.
Six, closures and lambda
This is also an example of Laosheng's long talk, and there are similar situations in other languages. Let's look at an example:
>>> def create_multipliers (): ... return [lambda x:i*x for I in range (5)]...>>>-multiplier in Create _multipliers (): ... print multiplier (2) ...
The return value of the Create_multipliers function is a list, and each element of the list is a function--a function that multiplies the input parameter x by a multiplier of I. The expected results are 0,2,4,6,8. But the result is 5 8, not surprisingly.
Because lambda is often used when this trap occurs, it may be considered a lambda problem, but Lambda says it is reluctant to carry the pot. The nature of the problem in Python with the attribute lookup rule, LEGB (Local,enclousing,global,bulitin), in the above example, I is in the closure scope (enclousing), and Python's closure is late binding, This means that the value of the variable used in the closure is obtained when the internal function is invoked.
The solution is also very simple, that is, the scope of the closure of the domain is a local scope.
>>> def create_multipliers (): ... return [lambda x, i = i:i*x for I in range (5)] ...
VII, define __DEL__
Most computer majors may be the first to learn C, C + +, the concept of construction, destructors should be very familiar. So, when switching to Python, it's natural to know that there are no corresponding functions. For example, in C + +, very well-known raii, that is, through the construction, destruction to manage resources (such as memory, file descriptor) of the declaration cycle. That in Python to achieve the same effect how to do, that needs to find an object in the destruction of the function must be called, so found the __init__, __del__ function, it may be simple to write two examples found that can also work. But in fact it may fall into a trap that is described in Python documnet:
Circular references which is garbage be detected when the option cycle detector is enabled (it's on by default), but can Only being cleaned up if there is no Python-level __del__ () methods involved.
Simply put, if an object in a circular reference defines a __del__, then the Python GC cannot be recycled, so there is a risk of a memory leak
The different poses import the same module
The example is slightly modified on the StackOverflow example, assuming there is now a package called MyPackage, which contains three Python files: mymodule.py, main.py, __init__.py. The mymodule.py code is as follows:
L = []class A (object): Pass
The 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__ ': impor T sys sys.path.append ('.. /') Add (1) ret = get () print "Lets check", ret
Running PYthon main.py, the results are as follows:
Updated list [1] 4406700752module in Get 4406700920lets check []
As you can see from the run result, the import mymodule in the Add and get functions are not the same module,id. Of course, in python2.7.10, you need the 13th line of main.py to have this effect. You might ask, who would write a code like line 13th? In fact, in many projects, in order to import the time convenient, will add a bunch of paths to sys.path. So in the project, it's very necessary to agree on an import approach.
Ninth, Python upgrade
Python3.x is not backwards compatible, so if you have to be careful when upgrading from 2.x to 3.x, here are two points:
In python2.7, the return value of range is a list, whereas in python3.x, a Range object is returned.
Map (), filter (), Dict.items () returns the list in python2.7, and returns an iterator in 3.x. Of course, most of the iterators are better choices, more pythonic, but there are shortcomings, that is, can only traverse once. On Instagram's share, it also mentions a bug that caused a pit daddy.
Tenth, Gil.
End With Gil, because Gil is a known flaw in Python!
Students from other languages may see Python with the threading module, take it to use, the results found that the effect is not right ah, then will spray, what ghost.
Summarize:
There is no doubt that Python is a very easy-to-learn and very powerful language. Python is very flexible and can be customized very strongly. At the same time, there are traps that make it clear that these traps can be better mastered and used in this language. This article lists some of the flaws in Python, which is an incomplete list, and you are welcome to add.
SOURCE Xybaby
Programmers are wrong for old drivers. List of Python traps and defects