【问题标题】:Why do python lists persist outside function scope while integers don't?为什么 python 列表会在函数范围之外持续存在,而整数则不会?
【发布时间】:2021-10-21 18:32:15
【问题描述】:

Python 工作,因此我可以在每次函数运行时更新 list

list_obj = list()
def increase_list_obj(list_obj, n):
    list_obj.append(n)

print(list_obj)
for n in range(3):
    increase_list_obj(list_obj, n)
    print(list_obj)

OUTPUT:

[]
[0]
[0, 1]
[0, 1, 2]

根据list 的持续存在方式,我希望我还可以在每次函数运行时更新int

int_obj = 0
def increase_int_obj(int_obj):
    int_obj += 1

print(int_obj)
for n in range(3):
    increase_int_obj(int_obj)
    print(int_obj)

OUTPUT:
0
0
0
0

EXPECTED:
0
1
2
3

为什么int 更新与list 更新的工作方式不同? 这两个对象的持久性和范围规则有何不同?

(我并不是要建议两者应该表现相同,我很好奇他们为什么不这样做)

要抢占有关如何更新 int 的答案:我意识到您可以通过从函数中返回 int 值来更新它:

int_obj = 0
def increase_int_obj_v2(int_obj):
    int_obj += 1
    return int_obj

print(int_obj)
for n in range(3):
    int_obj = increase_int_obj_v2(int_obj)
    print(int_obj)

OUTPUT:
0
1
2
3

谢谢!

【问题讨论】:

  • 在列表的情况下,您正在修改名称所指的对象的内容,在整数的情况下,您正在更改名称所指的内容(分配不同的对象)
  • 所有值位于一个空间中,独立于引用这些值的名称所在的任何范围。
  • 我强烈推荐阅读这篇文章:nedbatchelder.com/text/names.html

标签: python scope


【解决方案1】:

为了更好的理解,你需要了解一些概念

int 是不可变的,list 是可变的

可变和不可变对象列表 可变的内置类型的对象是:

  • 列表
  • 套装
  • 字典
  • 用户定义的类

不可变的内置类型的对象是:

  • 数字(整数、有理数、浮点数、小数、复数和布尔数)
  • 字符串
  • 元组
  • 冷冻套装
  • 用户定义的类(完全取决于用户来定义特征)

这是什么意思?

有关不可变和可变的更多信息,请阅读this

一些对象通过引用传递给函数,一些对象通过值传递 (more)

【讨论】:

  • 另外值得注意的是,不可变类型可以通过hash-函数进行散列,并用作例如dict键。见docs.python.org/3/library/…
  • 可变类型也可以被散列,只要它们的不可变部分用于计算散列。
  • @Tom 谢谢,我从你那里学到了一个好点。
【解决方案2】:

Python 中的对象可以在任何范围内进行修改。整数的问题是它们是不可变的对象,因此每当它们被修改时,它们都会创建一个新的自身副本,该副本仅存在于它创建的范围内。

另一方面,列表与大多数其他 Python 对象一样,将在适当的位置进行修改,以允许在当前范围内进行更改。

这是一个使用自定义对象的示例。

class HoldInt:
  def __init__(self, integer):
    self.integer = integer

int_obj = HoldInt(0)

def modify_int():
  int_obj.integer += 1

print(int_obj.integer)
modify_int()
print(int_obj.integer)
0
1

【讨论】:

  • 更准确地说,您不能修改int,因此无需实现int.__iadd__。当x.__iadd__ 不存在时,x += y 脱糖为x = x.__add__(y) 而不是x = x.__iadd__(y)
  • 谢谢!我喜欢这个答案,因为它结合了关于不可变对象的优点以及@PersianMan 和 user2390182 分别提出的范围含义。我希望我可以在几个答案中添加检查!
【解决方案3】:

如果函数中有赋值,则变量是局部变量,否则它们是全局变量:

 i += 1

是一个作业 (i = i + 1)!因此i是函数内的一个局部变量。

list_obj.append(n)

是一个突变!因此,list_obj 在封闭的命名空间中查找,该命名空间是全局命名空间。

旁注:+= 可以是可变类型的突变:list_obj += [n] 也可以是突变。

【讨论】:

  • 注意,+=始终的分配。在对可变类型进行操作时,这只是一种变异也是。它通常不重要,但是当您在函数内部使用 += 时,它会出现,而左侧不是本地的(它不​​会从全局读取并分配给本地,它只是随着 @ 而死987654330@),或者当您在不可变类型内的list 上使用它时,例如mylists = ([], []); mylists[0] += [1,2,3] 将爆炸(突变将发生,但重新分配 mylists[0] 的尝试将失败;只有 .extend 在这种情况下有效)。
猜你喜欢
  • 2021-08-24
  • 1970-01-01
  • 2014-05-26
  • 2019-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多