1. Slice does not perform boundary-crossing check and report errors

What would be the output of the following code?

list = ['a'.'b'.'c'.'d'.'e']
print list[10:]
Copy the code

The following code outputs an empty list [] without raising an IndexError. As expected, try to get the members of a list with an index that exceeds the number of members.

For example, trying to get list[10] and subsequent members will result in IndexError.

However, trying to get a slice of the list and starting with an index that exceeds the number of members does not produce an IndexError, but simply returns an empty list.

This can be a particularly nasty puzzle, since there are no bugs at runtime, making bugs hard to track down.

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?
Copy the code

What will be the output of lines 2,4,6,8? 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]
Copy the code

The output of the first line is intuitively easy to understand, for example list = [[]] * 5 simply creates five empty lists. However, the key point to understand about the expression list=[[]] * 5 is that it does not create a list containing five separate lists, but rather that it creates a list containing five references to the same list. Only with this in mind can we better understand the following output. 3. Here’s the kicker: delayed binding of closures

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

#Python Learning Exchange group: 531509025

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

print [m(2) for m in multipliers()]
Copy the code

How can you modify the multipliers definition above to produce the desired result? The above output is [6, 6, 6, 6], not [0, 2, 4, 6] as we expected.

The problem is caused by delayed binding of Python closures. This means that when an inner function is called, the value of the parameter is looked up inside the closure. Therefore, when any function returned by multipliers() is called, the value of I will be looked up in a nearby range. At that point, whether or not the returned function is called, the for loop is complete and I is given the final value of 3.

Therefore, each time the returned function is multiplied by the passed value of 3, since the previous code passed the value of 2, they all end up returning 6(3*2). As it happens, The Hitchhiker’s Guide to Python also points out that there is another widely misunderstood point about lambdas, but not in this case. There is nothing special about a function created by lambda expressions; it is the same function created by DEF.

Here are some ways to solve this problem.

One solution is to use Python generators.

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

Another solution is to create a closure that uses default functions to bind immediately.

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

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)]
Copy the code