title: 100 Helpful Python Tipssubtitle: 100 Helpful Python Tips
date: 2020-06-28
author: NSX
catalog: true
tags:
- Python
- Python Tips

尝试解决以下问题,然后检查以下答案:

  • 问题1:
  • 问题1
  • 问题1

    问题1

假设我们有两个变量:

  1. x = 1
  2. y = 2
  3. l = [x, y]
  4. x += 5
  5. a = [1]
  6. b = [2]
  7. s = [a, b]
  8. a.append(5)

l和s的输出是什么?

跳到解决方案1

问题2

让我们定义一个简单的函数:

  1. def f(x, s=set()):
  2. s.add(x)
  3. print(s)

What will happen if you call:

  1. >>f(7)
  2. >>f(6, {4, 5})
  3. >>f(2)

跳到解决方案2

问题3

让我们定义两个简单的函数:

  1. def f():
  2. l = [1]
  3. def inner(x):
  4. l.append(x)
  5. return l
  6. return inner
  7. def g():
  8. y = 1
  9. def inner(x):
  10. y += x
  11. return y
  12. return inner
  13. def h():
  14. l = [1]
  15. def inner(x):
  16. l += [x]
  17. return l
  18. return inner

以下命令将产生什么结果?

  1. >>f_inner = f()
  2. >>print(f_inner(2))
  3. >>g_inner = g()
  4. >>print(g_inner(2))
  5. >>h_inner = h()
  6. >>print(h_inner(2))

跳到解决方案3

问题4

Difference between zip(list) and zip(*list)

  1. p = [[1,2,3],[4,5,6]]
  2. >>>d=zip(p)
  3. >>>list(d)
  4. [([1, 2, 3],), ([4, 5, 6],)]
  5. >>>d=zip(*p)
  6. >>>list(d)
  7. [(1, 4), (2, 5), (3, 6)]

Answer:

zip wants a bunch of arguments to zip together, but what you have is a single argument (a list, whose elements are also lists). The * in a function call “unpacks” a list (or other iterable), making each of its elements a separate argument. So without the *, you’re doing zip( [[1,2,3],[4,5,6]] ). With the *, you’re doing zip([1,2,3], [4,5,6]).


解决方案1

  1. >>print(l)
  2. [1, 2]
  3. >>print(s)
  4. [[1, 5], [2]]

由于x是不可变的,因此该操作x+=5不会更改原始对象,而是会创建一个新对象。列表的第一个元素仍指向原始对象,因此其值保持不变。

如果对象是可变的a,则a.append(5)更改原始对象,因此列表s 的输出变了!

解决方案2

  1. >>f(7)
  2. {7}
  3. >>f(6, {4, 5})
  4. {4, 5, 6}
  5. >>f(2)
  6. {2, 7}

前两个输出是完全有意义的:首先将的值7添加到默认的空集结果中{7},然后将的值6添加到{4, 5}结果集中{4, 5, 6}

但是随后发生了一件奇怪的事情:的值2不是添加到默认的空集,而是添加到的集{7}。为什么?可选参数s的默认值仅被评估一次-仅在第一次调用期间s将被初始化为空集。因为在调用后s可变的f(7)所以对其进行了修改。第二个调用f(6, {4, 5})不会影响默认参数-提供的设置将其{4, 5}隐藏,换句话说,它{4, 5}是一个不同的变量。第三次调用f(2)使用的s变量与第一次调用中使用的变量相同,但不会将s重新初始化为空集,而是使用s的先前值{7}

这就是为什么 你不应该使用可变的默认参数。在这种情况下,应按以下方式修改功能:

  1. def f(x, s=None):
  2. if s is None:
  3. s = set()
  4. s.add(x)
  5. print(s)

解决方案3

  1. >>f_inner = f()
  2. >>print(f_inner(2))
  3. [1, 2]
  4. >>g_inner = g()
  5. >>print(g_inner(2))
  6. UnboundLocalError: local variable y referenced before assignment
  7. >>h_inner = h()
  8. >>print(h_inner(2))
  9. UnboundLocalError: local variable l referenced before assignment

In this problem we deal with closures — the fact that inner functions remember how their enclosing namespaces looked at the time of definition.

So what is happening? If you compared just the behavior of the first two functions, you could think that once again the difference has to do with l being a mutable list and x being an immutable string.

Looking at the example with the function h shows that there is something else to it. Here just like in the function f we are trying to alter a mutable list, but this time we fail. You would think that operations l.extend([x]) andl += [x] are equivalent, but in fact there is a subtle difference between them: behind the scenes l.extend will cause compiler to call LOAD_DEREF instruction which will load the non-local list l (and then the list will be modified), while with l += [x] the compiler will call LOAD_FAST which looks for the variable l to in the local scope of the inner function and therefore fails.

结论

注意可变变量和不可变变量之间的区别。

不要使用可变的默认参数。

在内部函数中更改闭包变量时要小心。使用nonlocal关键字声明该变量不是本地变量。

3. Get n largest or n smallest elements in a list using the module heapq

  1. import heapq
  2. scores = [51, 33, 64, 87, 91, 75, 15, 49, 33, 82]
  3. print(heapq.nlargest(3, scores)) # [91, 87, 82]
  4. print(heapq.nsmallest(5, scores)) # [15, 33, 33, 49, 51]

4. Pass values from a list as method arguments

We can extract all elements of a list using “*”:

  1. my_list = [1, 2, 3, 4]print(my_list) # [1, 2, 3, 4]
  2. print(*my_list) # 1 2 3 4

This can be helpful in situations where we want to pass all elements of a list as method arguments:

  1. def sum_of_elements(*arg):
  2. total = 0
  3. for i in arg:
  4. total += i
  5. return total
  6. result = sum_of_elements(*[1, 2, 3, 4])
  7. print(result) # 10

参考

Can you solve these 3 (seemingly) easy Python problems?