译者注:

  • 本文翻译自 Trey Hunner 于 2019 年 6 月 18 日发表的文章 Loop Better: a deeper look at iteration in Python
  • 文中括号或者引用块中的 斜体字 为对应的英文原文或者我自己注释的话(会标明「译者注」),否则为原文中本来就有的话
  • 文中的「我」均指原作者 Trey Hunner
  • 目录保留英文原文
  • 一些术语及特殊用语保留英文原文
  • 本人水平有限,如有错误欢迎指出
  • 能力尚可建议阅读英文原文
  • 本文同步发表在我的个人独立博客:理解 Python 中的 for 循环 · Lee’s Space Station

Python 中 for 循环的工作方式和其他编程语言的不太一样。本文中我们将会深入探索 Python 的 for 循环来了解他们是如何工作的,以及为什么这么是这种工作方式。

Note:本文基于我的 Loop Better 演讲,原本发表在 opensource.com。

Looping Gotchas

我们将通过一些「gotchas」(陷阱)来开始今天的旅程。等我们知道 Python 中的 for 循环的原理时,我们再回过头来看这些 gotchas,并解释原因。

Gotcha 1: Looping Twice

假设我们有一个数字 list(列表)以及一个生成这些数字的平方的 generator(生成器):

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

我们可以将我们的 generator 对象传给 tuple 构造函数来变成一个 tuple(元组):

>>> tuple(squares)
(1, 4, 9, 25, 49)

之后如果我们将同样的 generator 对象传给 sum 函数,我们可能希望返回这些数字的和,也就是 88。

>>> sum(squares)
0

但是我们得到的是 0

Gotcha 2: Containment Checking

我们还用上面相同的数字 list 和 generator 对象:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

如果我们问 9 是否在 squares 中,那么 Python 会告诉我们在。但是当我们再问一次时,回答是不在。

>>> 9 in squares
True
>>> 9 in squares
False

我们把一个问题问了两遍,但是 Python 给了两个不同的回答。

Gotcha 3: Unpacking

这个 dictionary 有两个键值对:

>>> counts = {'apples': 2, 'oranges': 1}

让我们用 multiple assignment 来解包(unpack)这个 dictionary:

>>> x, y = counts

你可能期望的是当我们解包这个 dictionary 时,我们会得到键值对,或者发生错误。

但是解包 dictionary 并不会有任何错误发生,也没有得到键值对,反而你得到的是键:

>>> x
'apples'

当我们学到这写代码片段背后的逻辑时,我们再回过头来看这些代码。

Review: Python’s for loop

Python 中的 for 循环不是传统的 for 循环。为了解释我的意思,我们来看一下其他语言的 for 循环是怎么写的。

这是一个用 JavaScript 写的传统的 C 风格的 for 循环:

let numbers = [1, 2, 3, 5, 7];
for (let i = 0; i < numbers.length; i += 1) {print(numbers[i])
}

JavaScript、C、C++、Java、PHP 以及其他一大堆都是这种 C 风格的 for 循环,但是 Python 不是

Python 没有 C 风格的 for 循环,但是的确有 for 循环,但是原理类似于 foreach 循环。

这是 Python 的 for 循环风格:

numbers = [1, 2, 3, 5, 7]
for n in numbers:print(n)

不像传统的 C 风格的 for 循环,Python 的 for 循环没有索引变量。没有索引初始化、边界检查和索引增加。Python 的 for 循环都把这些工作为我们做了。

所以在 Python 中确实有 for 循环,但不是传统的 C 风格的 for 循环。我们称之为 for 循环的东西的工作方式很不一样。

Definitions: Iterables and Sequences

现在我们已经知道 Python 的 for 循环没有索引,接下来先让我们做一些定义。

Python 中任何你可以通过 for 循环来循环的东西都是一个 iterable(可迭代对象)。iterable 可以被循环,任何可被循环的东西都是一个 iterable。

for item in some_iterable:print(item)

Sequences 是一种非常常见的 iterable 类型。 Lists、tuples、和 strings 都是 sequences。

>>> numbers = [1, 2, 3, 5, 7]
>>> coordinates = (4, 5, 7)
>>> words = "hello there"

Sequences 是具有一组特定特征的 iterable。他们可以从 0 开始索引,并结束于长度 -1,他们有长度(length),可以被切片(sliced)。Lists、tuples、strings 和 其他所有的 sequences 都是这样。

>>> numbers[0]
1
>>> coordinates[2]
7
>>> words[4]
'o'

Python 中许多东西都是 iterable,但并不是所有的 iterable 都是 sequences。Sets(集合)、dictionaries、files 和 generators 都是 iterable,但他们都不是 sequences。

>>> my_set = {1, 2, 3}
>>> my_dict = {'k1': 'v1', 'k2': 'v2'}
>>> my_file = open('some_file.txt')
>>> squares = (n**2 for n in my_set)

所以任何可以用 for 循环来循环的东西都是一个 iterable,sequences 是一种 iterable 类型,但是 Python 也有许多其他类型的 iterable。

Python’s for loops don’t use indexes

你可能会认为 Python 的 for 循环本质上还是用的索引。下面我们使用 while 循环和索引来遍历一个 iterable:

numbers = [1, 2, 3, 5, 7]
i = 0
while i < len(numbers):print(numbers[i])i += 1

这种方式适合 lists,但是不是任何对象都可以这么用。这种方式只适合 sequences。

如果我们试图对一个 set 进行上述遍历,我们会得到一个错误:

>>> fruits = {'lemon', 'apple', 'orange', 'watermelon'}
>>> i = 0
>>> while i < len(fruits):
...     print(fruits[i])
...     i += 1
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: 'set' object does not support indexing

Sets 不是 sequences,所以他们不支持索引。

Python 中我们不能使用索引来遍历每一个 iterable。这对于非 sequences 的 iterable 不起作用。

Iterators power for loops

目前为止我们已经看到 Python 不可能使用索引来进行循环。相反,Python 的 for 循环使用 iterator(迭代器)。

Iterators 就是增强 iterable 的东西。你可以从任何一个 iterable 得到一个 iterator。你可以使用 iterator 手动遍历一个 iterable。

让我们看看怎么实现。

这里有三个 iterable:一个 set,一个 tuple,一个 string:

>>> numbers = {1, 2, 3, 5, 7}
>>> coordinates = (4, 5, 7)
>>> words = "hello there"

我们可以使用 Python 的内置函数 iter 来把这些 iterable 变成 iterator。将一个 iterable 作为参数传给 iter 总是会返回一个 iterator,无论 iterable 是什么类型。

>>> iter(numbers)
<set_iterator object at 0x7f2b9271c860>
>>> iter(coordinates)
<tuple_iterator object at 0x7f2b9271ce80>
>>> iter(words)
<str_iterator object at 0x7f2b9271c860>

一旦我们有了一个 iterator,我们就可以使用内置的 next 函数来获取下一项。

>>> numbers = [1, 2, 3]
>>> my_iterator = iter(numbers)
>>> next(my_iterator)
1
>>> next(my_iterator)
2

Iterators 是有状态的,意味着一旦你消耗了一项那这项就消失了。

如果你用 next 取下一项然而这时候已经没有下一项的时候,你就会得到一个 StopIteration 错误:

>>> next(iterator)
3
>>> next(iterator)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration

所以你可以从每一个 iterable 得到一个 iterator。对于 iterator 你可以做得唯一的一件事就是使用 next 函数取其下一项。但如果已经没有下一项了,那么你就会得到一个 StopIteration 错误。

Looping without a for loop

现在我们已经学习了 iterator 以及 nextiter 函数。我们将要尝试不通过 for 循环来遍历一个 iterable。

我们尝试将 for 循环转成 while 循环:

def funky_for_loop(iterable, action_to_do):for item in iterable:action_to_do(item)

要做到这一点,我们将:

  1. 从给定的 iterable 获得一个 iterator
  2. 从得到的 iterator 中重复获取下一项
  3. 如果成功获取到下一项,执行 for 循环的主体
  4. 如果得到一个 StopIteration 错误,停止循环
def funky_for_loop(iterable, action_to_do):iterator = iter(iterable)done_looping = Falsewhile not done_looping:try:item = next(iterator)except StopIteration:done_looping = Trueelse:action_to_do(item)

我们刚刚只是用 while 循环和 iterator 重新发明了一个 for 循环。

上面的代码很好的展现了 Python 中的循环是如何工作的。如果你理解了内置函数 iternext 是如何作用于循环的,那么你就理解了 Python for 循环的工作方式。

事实上相比理解 for 循环的工作方式,你会了解的更多。所有循环都是这么工作的。

Iterator protocol迭代器协议)描述了 Python 中循环的工作方式。它本质上是 iternext 函数工作方式的定义。Python 中的所有迭代形式都由 iterator protocol 提供支持。

for 循环使用的就是 iterator protocol(就像我们所看到的):

for n in numbers:print(n)

Multiple assignment 也使用 iterator protocol:

x, y, z = coordinates

Star expressions(星号表达式)也使用 iterator protocol:

a, b, *rest = numbers
print(*numbers)

还有许多内置函数都依赖 iterator protocol:

unique_numbers = set(numbers)

Python 中与 iterable 一起使用的任何东西都可能以某种方式使用 iterator protocol。每当你在 Python 中循环迭代时,你就依赖于 iterator protocol。

Generators are iterators

你可能会想:iterators 很厉害,但是他们好像只是一种实现细节,作为 Python 用户我们似乎并不关心这个。

我可以告诉你的是:在 Python 中直接使用 iterator 是很常见的。

这里的 squares 对象是一个 generator:

>>> numbers = [1, 2, 3]
>>> squares = (n**2 for n in numbers)

Generators 就是一种 iterators,意味着你可以使用 next 函数来获取下一项:

>>> next(squares)
1
>>> next(squares)
4

如果你之前使用过 generators,那么你就知道你可以使用循环来遍历他们:


>>> squares = (n**2 for n in numbers)
>>> for n in squares:
...     print(n)
...
1
4
9

在 Python 中如果一个对象可以被循环,那么这就是一个 iterable。(目前为止作者好像已经提了很多次 ?

所以 generators 是 iterator,但 generators 也是 iterable。为什么?

I lied to you

当我之前解释 iterator 是如何工作的时候,我跳过了一个重要的细节。

Iterators 是 iterable.

我再说一遍:Python 中每一个 iterator 也是一个 iterable,意味着你可以遍历他们。

由于 iterator 也是 iterable,你也可以使用 iter 函数从一个 iterator 得到一个 iterator:

>>> numbers = [1, 2, 3]
>>> iterator1 = iter(numbers)
>>> iterator2 = iter(iterator1)

记住当我们将一个 iterable 穿给 iter 函数的时候我们就可以得到一个 iterator。(真的重复很多遍了。。。

当我们将 iterator 传给 iter 函数时总是会返回他自己:

>>> iterator1 is iterator2
True

Iterators 都是 iterable,所有的 iterator 都是他们自己的 iterators。

有点迷是吗?

让我们回顾下这些术语。

你可以遍历一个 iterable,而 iterator 就是实际执行遍历操作的代理。

另外,Python 中 iterator 也是 iterable,而且他们也是自己的 iterators。(我真的不想再说这个了。。。

所以 iterator 是 iterable,但是他们没有一些 iterable 所拥有的特性。

Iterators 没有长度,他们不能使用索引:

>>> numbers = [1, 2, 3, 5, 7]
>>> iterator = iter(numbers)
>>> len(iterator)
TypeError: object of type 'list_iterator' has no len()
>>> iterator[0]
TypeError: 'list_iterator' object is not subscriptable

作为 Python 程序员的我们来说,iterators 唯一有用的是可以使用 next 函数获取其下一项:


>>> next(iterator)
1
>>> list(iterator)
[2, 3, 5, 7]

如果我们对一个 iterator 遍历第二次,那么我们什么也得不到:

>>> list(iterator)
[]

你可以把 iterator 看成是 lazy iterable,只能用一次,也就是只能遍历一次。

Object Iterable? Iterator?
Iterable ✔️
Iterator ✔️ ✔️
Generator ✔️ ✔️
List ✔️

正如上面的真值表所展示的,iterable 不总是 iterators,但是 iterator 总是 iterable。

The iterator protocol, in full

让我们从 Python 的角度定义 iterator 是如何工作的。

iterable 可以作为参数传入 iter 函数来得到一个 iterator。

Iterators:

  1. 可以作为参数传入 next 函数来获取下一项,当没有元素时抛出 StopIteration 异常
  2. 可以作为参数传入 iter 函数,返回他们本身

这些命题的逆命题也同样成立:

  1. 任何可以传入 iter 并没有抛出 TypeError 异常的对象都是 iterable
  2. 任何可以传入 next 并没有抛出 TypeError 异常的对象都是 iterator
  3. 任何可以传入 iter 并返回他们本身的对象都是 iterator

这就是 Python 中的 iterator protocol。

Iterators enable laziness

Iterators 允许我们创建并使用 lazy iterable,在我们要求获取下一项之前他们不会做任何事。由于我们可以创建 lazy iterable,我们可以创建无限长的 iterable。我们也可以创建保有系统资源(are conservative with system resources)的 iterable,可以为我们节省内存和 CPU 时间。

Iterators are everywhere

在 Python 中你已经见过很多 iterator 了。我之前已经提到 generator 就是 iterator 了。许多 Python 的内置类也是 iterator。例如 enumeratereversed 都是 iterator。

>>> letters = ['a', 'b', 'c']
>>> e = enumerate(letters)
>>> e
<enumerate object at 0x7f112b0e6510>
>>> next(e)
(0, 'a')

在 Python 3 中,zipmapfilter 也是 iterator。

>>> numbers = [1, 2, 3, 5, 7]
>>> letters = ['a', 'b', 'c']
>>> z = zip(numbers, letters)
>>> z
<zip object at 0x7f112cc6ce48>
>>> next(z)
(1, 'a')

而且文件对象也是 iterator。

>> next(open('hello.txt'))
'hello world\n'

Python 中有许多内置的 iterator,第三方包中也有许多。这些 iterator 就像 lazy iterable,他们不会做任何事,直到你要求获取下一项。

Creating your own iterator

你可能已经在使用 iterator 了,但是我想让你知道的是你可以创建你自己的 iterator 和 lazy iterable。

下面这个类创建了一个 iterator,接受一个数字的 iterable 作为输入,并且当循环的时候输出每一个数字的平方。

class square_all:def __init__(self, numbers):self.numbers = iter(numbers)def __next__(self):return next(self.numbers) ** 2def __iter__(self):return self

但是任何事情都不会发生直到我们开始循环该类的实例。

这里我们有一个无限长的 iterable countsquare_all 可以接受 count 作为参数而无需完全遍历 count

>>> from itertools import count
>>> numbers = count(5)
>>> squares = square_all(numbers)
>>> next(squares)
25
>>> next(squares)
36

这个 iterator 类是没问题的,但是通常我们不会这么写。通常当我们想要创建一个自定义 iterator 的时候,我们会创建一个 generator 函数:

def square_all(numbers):for n in numbers:yield n**2

这个 iterator 函数和上面的类是等价的,工作方式也是一样的。

这个 yield 语句看起来比较神奇,但是确实很强大:yield 函数允许我们在下一次 next 函数调用前暂停。Generator 函数和普通函数的区别就在于 yield 语句。

实现上述相同的 iterator 的另一种方式是使用 generator expression(生成器表达式)。

def square_all(numbers):return (n**2 for n in numbers)

这个和 generator 函数是一样的,只是语法类似于 list comprehension(列表推导式)。如果你的代码中需要 lazy iterable,可以考虑下用 generator 函数或者 generator expression 来创建一个 iterator。

How iterators can improve your code

一旦你接受了在代码中使用 lazy iterable 的思想,那么你就会发现很多时候都可以创建一个帮助函数来协助循环和处理数据。

Laziness and summing

这是个 Django 的查询集(queryset)用于对所有计费小时数(billable hours)求和的 for 循环:

hours_worked = 0
for event in events:if event.is_billable():hours_worked += event.duration

下面是 generator expression 版本:

billable_times = (event.durationfor event in eventsif event.is_billable()
)hours_worked = sum(billable_times)

注意到代码已经发生了很大变化。

上面这种使用 lazy iterable 的方式允许我们命名之前没有命名的东西(billable_times),也可以使用 sum 函数。之前我们不能使用 sum 函数是因为我们没有一个 iterable。Iterator 可以让我们从根本上改变代码的组织方式。

Laziness and breaking out of loops

下面的代码输出一个日志文件的前 10 行:

for i, line in enumerate(log_file):if i >= 10:breakprint(line)

下面的代码实现了同样的功能,但是我们使用了 itertools.islice 函数来实现「懒加载」:

from itertools import islicefirst_ten_lines = islice(log_file, 10)
for line in first_ten_lines:print(line)

我们这里创建的 first_ten_lines 变量是个 iterator。再次说下有了 iterator 我们就可以命名之前不能命名的东西(first_ten_lines)。这样有助于使我们的代码可读性更强。

此外我们也不用再写 break 语句了,因为 islice 函数已经帮我们做了。

你可以在内置库 itertools 和 第三方库如 boltons 和 more-itertools 中找到许多 iterator 相关函数。

Creating your own iteration helpers

你可以再内置库或者第三方库中找到一些 iterator 的帮助函数,但是你也可以自己写!

下面的代码用于计算一个序列中相邻两个数字的差,返回一个 list。

current = readings[0]
for next_item in readings[1:]:differences.append(next_item - current)current = next_item

注意这个代码需要在每一次循环中额外的给一个变量赋值。同时这个代码也只适用于有索引功能的对象,比如 sequence。如果 readings 是一个 generator,一个 zip 对象,或者其他类型的 iterator,那么这个代码就不能用了。

让我们来写一个帮助函数来修复这个问题。

这是一个 generator 函数,对于一个 iterable,在每次循环中输出当前项和下一项:

def with_next(iterable):"""Yield (current, next_item) tuples for each item in iterable."""iterator = iter(iterable)current = next(iterator)for next_item in iterator:yield current, next_itemcurrent = next_item

这里我们手动从 iterable 得到了一个 iterator,使用 next 函数获取下一项(译者注:即第一项),然后在遍历 iterator 来获取后面所有项,同时追踪最后一项。这个函数不仅适用于 sequence,也适用于所有的 iterable 对象。

下面的代码使用上面的 with_next 函数实现了相同的功能,不用再手动追踪 next_item 了(译者注:但是在函数里面。。。):

differences = []
for current, next_item in with_next(readings):differences.append(next_item - current)

注意我们不必在循环中略显笨拙地对 next_item 进行赋值,with_next 函数帮我们做了这些工作。

同时这个代码也足够紧凑,如果需要的话我们甚至可以转换成一个 list comprehension。

differences = [(next_item - current)for current, next_item in with_next(readings)
]

Looping Gotchas: Revisited

此时我们可以回到刚开始我们提到的那些奇怪的问题,让我们来搞清楚发生了什么。

Gotcha 1: Exhausting an Iterator

这里我们有一个 generator 对象,squares

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

如果把他传入 tuple 构造函数,那么我们会得到一个 tuple:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)
>>> tuple(squares)
(1, 4, 9, 25, 49)

然后如果我们计算这个 generator 中所有数字的和,那么结果就会是 0

>>> sum(squares)
0

因为此时这个 generator 已经是空的了,我们已经消耗完了(译者注:遍历完了)。如果我们再次使用 tuple 构造函数,那么就会得到一个空的 tuple:

>>> tuple(squares)
()

Genetor 是一种 iterator,iterator 是只能使用一次的 iterable。

Gotcha 2: Partially-Consuming an Iterator

同样我们有一个 generator 对象,squares

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)

如果我们要查询 9 是否在其中,那么我们会得到 True

>>> 9 in squares
True

但如果我们再查一次,就会得到 False

>>> 9 in squares
False

当我们第一次查询 9 是否存在时,Python 就会去遍历这个 generator。如果在此之后我们继续遍历这个 generator,那么只能得到最后两个数字,因为前面的数字都已经遍历过了,已经没了:

>>> numbers = [1, 2, 3, 5, 7]
>>> squares = (n**2 for n in numbers)
>>> 9 in squares
True
>>> list(squares)
[25, 49]

查询某对象是否在一个 iterator 中的时候会部分消耗(译者注:遍历)这个 iterator。如果不循环我们是没办法知道一个对象是否在 iterator 中的。

Gotcha 3: Unpacking is iteration

当你遍历 dict 的时候得到的是 key:


>>> counts = {'apples': 2, 'oranges': 1}
>>> for key in counts:
...     print(key)
...
apples
oranges

当你解包(unpack)一个 dict 的时候,你得到的也是 key:


>>> x, y = counts
>>> x, y
('apples', 'oranges')

循环依赖于 iterator protocol。解包 iterable 同样依赖于 iterator protocol。解包 dict 和遍历 dict 是一样的,都是使用的 iterator protocol,所以得到的结果是一样的。

Recap and related resources

Sequence 是 iterable,但不是所有的 iterable 都是 sequence。当某个人说 「iterable」的时候,你可以假定他说的是「你可以遍历的东西」,但是不要假定你可以遍历两次,查询长度或者索引。

Iterator 是 Python 中最基本的 iterable 形式。如果你在代码中想要一个 lazy iterable,那么考虑 iterator,创建一个 generator 函数或者 generator expression。

最后请记住,Python 中的每种类型的遍历都依赖于 iterator protocol,因此理解 iterator protocol 是了解 Python 中循环的关键。

这里是我推荐的一些相关文章和视频:

  • Loop Like a Native,Ned Batchelder 在 PyCon 2013 上的演讲
  • Loop Better,这篇文章对应的演讲【YouTube】
  • The Iterator Protocol: How For Loops Work,我写的关于 iterator protocol 的一篇短文
  • Comprehensible Comprehensions,我关于 comprehension 和 generator expression 的演讲【YouTube】
  • Python: range is not an iterator,我的关于 range 和 iterator 的文章
  • Looping Like a Pro in Python,DB 在 PyCon 2017 上的演讲

译者后记:

  • 按照译者理解,iterable、iterator 和 generator 的范围大小是:iterable > iterator > generator,generator 是 iterator 的子类型,详细参见 Python Generators vs Iterators - Comparison Between Python Iterators and Generators - DataFlair

理解 Python 中的 for 循环相关推荐

  1. 深入理解python中的for循环语句

    公众号:尤而小屋 作者:Peter 编辑:Peter 大家好,我是Peter~ 一年四季,循环往复:说到底就是一个循环的问题 for语句实际上解决的是循环问题.在很多的高级语言中都有for循环(for ...

  2. python中for循环语句格式_关于Python中的for循环控制语句

    #第一个:求 50 - 100 之间的质数 import math for i in range(50, 100 + 1): for j in range(2, int(math.sqrt(i)) + ...

  3. 深入理解Python中的全局解释锁GIL

    深入理解Python中的全局解释锁GIL 转自:https://zhuanlan.zhihu.com/p/75780308 注:本文为蜗牛学院资深讲师卿淳俊老师原创,首发自公众号https://mp. ...

  4. 由浅入深|让你彻底理解Python中的yield

    没有用过的东西,没有深刻理解的东西很难说自己会,而且被别人一问必然破绽百出.虽然之前有接触过python中的生成器的概念,但是只是走马观花,这两天的一次交谈中,别人问到了生成器,顿时语塞,死活想不起来 ...

  5. python iterable对象_如何理解Python中的iterable对象

    转载请注明出处:https://www.jianshu.com/u/5e6f798c903a [^*] 表示注脚,在文末可以查看对应连接,但简书不支持该语法. 首先,容器和 iterable 间没有必 ...

  6. python中for无限循环_关于循环:在Python中从1循环到无穷大

    在C语言中,我会这样做: 1 2 3 4int i; for (i = 0;; i++) if (thereIsAReasonToBreak(i)) break; 如何在Python中实现类似的功能? ...

  7. 更深入理解 Python 中的迭代

    (点击上方公众号,可快速关注) 编译: linux中国 / MjSeven   英文:  Trey Hunner https://linux.cn/article-9681-1.html 深入探讨 P ...

  8. 理解Python中的yield

    理解Python中的yield 参考文献 本文浅谈自己对Python中yield关键字的理解. yield可以理解成return,但是它与return又不完全相同.在Python中,yield关键字是 ...

  9. python参数传递方法_深入理解python中函数传递参数是值传递还是引用传递

    python 的 深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是&q ...

最新文章

  1. Android offsetTopAndBottom 和 setTranslationY 的作用 和区别
  2. 【重复制造精讲】REM Pull List 拉料单(续)
  3. 【收藏】K8S部署minio对象存储
  4. 深度学习笔记(27) 经典卷积网络
  5. SAP License:电子行业ERP实施
  6. Fiddler抓取APP数据包实践教程
  7. [SSH] 设置密钥登陆
  8. golang slice分割和append copy还是引用
  9. c语言通讯录感想,C语言通讯录实例分享
  10. 建模的计算机基础理论,数学建模基础理论
  11. 重新理解泰勒公式 牛顿法
  12. mysql 关于 不可重复读与幻读的解决方案
  13. java 线程 设计模式_Java多线程设计模式(四)
  14. 【Typora启动报错】This beta version of Typora is expired, please download and install a newer version.
  15. Windows XP 共享 Workgroup无法访问.您可能没有权限使用网络资源
  16. 今日头条文章量如何打造爆款
  17. zeros什么意思_matlab中zeros函数是什么含义?MATLAB中zeros表示表示什么意思
  18. 通过singlefile把网页保存到本地
  19. 大数据学习路线-入门精简
  20. 牛客网 哈夫曼树 (大根堆、哈夫曼树)

热门文章

  1. 【论文阅读】Local residual similarity for image re-ranking
  2. 可以产生粗体字的html标签是,下列可以产生粗体字的 HTML 标签是______
  3. 人口数据可视化,深圳是人口密度最高的城市,东莞上海位居二三名
  4. N1如何从无灯固件刷回Android官改
  5. 网佳创投创始人唐滔:创业者融资犹如交女友,围而不追,重在吸引
  6. 2022年中级会计实务考试冲刺题及答案
  7. CyberOptics将在韩国SEMICON展会上推出WaferSense® Auto Resistance Sensor
  8. LeetCode326. Power of Three一行代码解决
  9. webservice mysql配置文件_在WebService中使用Microsoft.Practices.EnterpriseLibrary.Data配置数据库...
  10. u3d实现滚动下拉(scrollview实现)