什么时候可以在函数调用中更改变量?

保罗·鲁宾斯坦

在Python中,可以更改函数中的某些类型的对象而不必返回任何内容。对于某些对象,情况并非如此。

例如,如果我们将字典传递给函数并在函数中对其进行更改,则原始字典将被更改:

def add_key(d, key):
    d[key] = True

d = {}
print d
# {}

add_key(d, 1)
print d
# {1: True}

相反,我们不能像这样更改整数:

def increment_int(i):
    i += 1

i = 1
print i
# 1

increment_int(i)
print i
# still 1!

起初,我认为也许规则只是不能以这种方式在函数内更改不可变对象。一个类似的示例不适用于字符串:

def append_string(s1, s2):
    s1 += s2

s = "hello"
print s
# "hello"

append_string(s, " world")
print s
# "hello", not "hello world" :( 

不过,我感到困惑,因为似乎某些操作应用于函数内可变对象的操作将在以后可见,而其他操作则不可见。例如,将项目附加到列表确实可以:

def append_list(l, val):
    l.append(val)

l = []
print l
# []

append_list(l, 1)
print l
# [1]

而交换两个列表的名称则不会:

def swap_lists(l1, l2):
    l1, l2 = l2, l1

l1 = [1]
l2 = [2]
print l1, l2
# [1] [2]

swap_lists(l1, l2)
print l1, l2
# still [1] [2], even though lists are mutable!

又一个具有看似奇怪和意外行为的示例:

def swap_then_append(l1, l2):
    l1, l2 = l2, l1
    l1.append(1)
    l2.append(2)

l1 = []
l2 = []
print l1, l2
# [] []

swap_then_append(l1, l2)
print l1, l2
# [2] [1]

有人可以解释这里发生了什么吗?


编辑:已确定此问题可能重复项那里的答案部分地告诉了我发生了什么,但是我仍然不明白为什么,例如,swap_lists上面的函数实际上并未交换列表。现在,我在进一步思考,我仍然不真正理解为什么increment_int以及append_string超出了我最初期望的范围,除了它与整数和字符串的不变性有关。

音农桑德斯

dupe目标中的解释可以很好地说明发生了什么,但是我将介绍发生的情况swap_then_append

def swap_then_append(l1, l2):
    print l1,l2
    # [3],[4]
    l1, l2 = l2, l1
    print l1,l2
    # [4] [3]
    l1.append(1)
    l2.append(2)

l1 = [3]
l2 = [4]
print l1, l2
# [3] [4]

swap_then_append(l1, l2)
print l1, l2
# [3,2] [4,1]

“交换”更改用于引用列表的变量的名称,但仅在函数中虽然基础对象的突变是永久的,但变量的分配取决于范围。l1l2在功能上还不如叫别的东西,因为他们现在只是阴影原始变量l1,并l2在函数签名,这反过来,阴影的定义l1,并l2在主脚本中定义。然后将这些突变应用于原始列表。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

什么时候可以并行使用可变变量调用函数?

什么时候可以安全地在构造函数和析构函数中调用this->

在Java中,什么时候调用枚举常量的构造函数?

什么时候构造函数调用中的堆栈对象?

什么时候在反应中调用useEffect挂钩清理函数

什么时候应该将函数存储到变量中?

什么时候可以调用getMeasuredWidth()

什么时候可以调用onTaskRemoved()?

什么时候使用()调用函数?

什么时候调用 getSchema 函数?

递归函数可以在函数的原始调用中更改变量吗?

函数什么时候可以返回引用?

OFS什么时候改变?

在Android中,什么时候调用Interface?

什么时候可以/可以在C ++中内联函数?可以强制内联行为吗?

什么时候可以调用带有标签参数且没有标签的函数?

什么时候在C ++中调用要调用的对象的析构函数?

Javascript中的didSet:更改变量时调用函数

什么时候创建局部变量,什么时候调用对象方法?

什么时候调用复制构造函数或赋值构造函数?

什么时候应该添加“&”,什么时候不应该使用C语言调用函数?

在函数中更改变量

什么时候应该直接使用Get方法与调用变量?

我什么时候可以在JavaScript中的变量名之前使用var?

我们什么时候调用事实上的装饰器中的内部函数?

什么时候在堆中的对象上调用C ++析构函数?

什么时候将函数添加到调用堆栈中?

什么时候函数将在C ++中包含堆栈_Unwind_Resume调用?

什么时候以及如何在JavaScript中调用此函数?