Fuzzy Semantics in Python Grammar

  • 2021-12-12 09:01:49
  • OfStack

Directory 1. Slice does not perform out-of-bounds checking and error reporting 2. Creation of empty list 3. Delayed binding of closures

1. Slices do not perform cross-border inspection and error reporting

What will be the output of the following code?


list = ['a', 'b', 'c', 'd', 'e']
print list[10:]


The following code will output an empty list [] and will not produce IndexError Error. As expected, try to get the members of a list with an index that exceeds the number of members.

For example, try to get the list[10] And subsequent members, will cause IndexError .

However, trying to get a slice of the list, the starting index Exceeding the number of members does not generate IndexError, Instead, only one empty list is returned.

This becomes a particularly disgusting intractable disease, because there are no errors when running, which makes bug difficult to track.

2. Create an empty list


1ist = [[ ]] * 5
list  # output?
list[0].append(10)
list  # output?
list[1].append(20)
list  # output?
list.append (30)
list  # output?


What results will lines 2, 4, 6, and 8 output? Try to explain.

The output is as follows:


[[],[],[],[],[]]
[[10],[10],[10],[10],[10]]
[[10,20],[10,20],[10,20]]
[[10,20],[10,20],[10,20],[10,20],[10,20],30]


The output from Line 1 is intuitively easy to understand, for example list = [ [ ] ] * 5 Simply create 5 empty lists. However, understanding the expression list=[ [ ] ] * 5 The key point is that instead of creating a list that contains five separate lists, it is creating a list that contains five references to the same list. Only by understanding this point can we better understand the following output results.

3. Delayed binding of closures

What will be the output of the following code? Please explain.


'''
 No one answers the problems encountered in study? Xiaobian created 1 A Python Learning and communication group: 531509025
 Looking for like-minded friends and helping each other , There are also good video learning tutorials and PDF E-books! 
'''
def multipliers():
    return [lambda x : i*x for i in range(4)]

print [m(2) for m in multipliers()]


How do you modify the above multipliers The definition of produces the desired result?
The output of the above code is [6, 6, 6, 6] Not what we think [0, 2, 4, 6] .

The causes of the above problems are list[10] 0 Delayed binding of closures. This means that when the internal function is called, the value of the parameter is searched within the closure. Therefore, when any multipliers() When the returned function is called, the value of i will be searched in a nearby range. At that point, the for loop is complete and i is assigned the final value of 3, regardless of whether the returned function is called or not.

Therefore, every time the function returned is multiplied by the passed value of 3, because the passed value of the previous code is 2, they all end up returning 6 (3*2). It happens that ,《The Hitchhiker's Guide to Python》 It is also pointed out that there is also a widely misunderstood knowledge point related to lambdas function, but with this case Not one. By lambda There is nothing special about the function created by the expression, which is actually like the function formula 1 created by def.

Here are some ways to solve this problem.

One solution is to use Python generator.


def multipliers():
    for i in range(4): yield lambda x : i * x


Another solution is to create a closure and bind it immediately with the default function.


def multipliers():
    return [lambda x, i=i : i * x for i in range(4)]


An alternative is to use partial functions:


from functools import partial
from operator import mul

def multipliers():
    return [partial(mul, i) for i in range(4)]

Related articles: