python 中参数变量的范围是什么?

What is the scope of argument variables in python?

考虑以下情况:

案例 1:

def fun(arg):
    
    arg += 1
    
my_var = 1
fun(my_var)
print(my_var)
>> 1

案例 2:

def fun(arg):
    
    arg += [4]
    
my_var = [1,2,3]
fun(my_var)
print(my_var)
>> [1, 2, 3, 4]

案例 3:

def fun(arg):
    
    arg = arg + [4]
    
my_var = [1,2,3]
fun(my_var)
print(my_var)
>> [1, 2, 3]

案例 4:

def fun(arg):
    
    print(arg)

fun("Hi")
print(arg)
>> Hi
Traceback (most recent call last):
  File "<string>", line 8, in <module>
NameError: name 'arg' is not defined

案例 4 表明参数变量的范围在函数内。案例 1 和案例 3 支持,因为对函数内 arg 变量的更改不会反映在全局参数中。

但是为什么会发生第二种情况呢?当我使用 append 而不是 += 时,我注意到了同样的事情。发生在 arg 上的更改不应该对从不同范围调用函数的变量产生任何影响吗?

感谢任何帮助。提前致谢。

答案很简单:函数参数是局部变量!

更多观察:

= 是赋值运算符并重新绑定一个变量。这将永远不会改变对象(ecxeption 切片分配)。

+= 是它自己的运算符,并作为可变类型的突变实现。您可以通过实现 __iadd__ dunder 方法为您自己的类型实现它的行为。 因此,一般来说,a = a + b 等同于 a += b!

对于列表,a += b 对应于 a.extend(b)。另一方面,a + b 创建一个 new 列表对象,a = a + b 将变量 a 重新绑定到该新对象。

案例 2 是唯一一个在实例上使用变异方法的案例。这会影响传递的参数。

其他人什么也不做,或者只是重新分配参数。 python 中的赋值仅影响被赋值的变量,而不影响仍引用前一个实例的其他变量。

强制性 link 到 Ned Batchelder

Python 让您可以简单地通过为变量赋值来创建变量,而无需预先声明变量。分配给变量的值决定了变量类型。

如果你在每个函数上打印变量类型,你就会看到它。

#case 2
def fun2(arg2):
    
    arg2 += [4]
    
my_var2 = [1,2,3]
#fun(my_var2)
print(type(my_var2))
print(type(my_var2[0]))

#case 4 where no type assigned
def fun4(arg44):
    
    print(arg)

#fun(myvar4)
print(arg4)

Watch this code in action with a visual explanation.

在函数内声明的任何变量都是局部的,但列表和字典的行为有点不同。即使不写 global list_name 也可以将元素附加到列表 在函数内部也不会将列表作为参数传递给函数。只有 lists 和 dict 是这样的。然而,案例 2 和案例 3 的差异似乎是一个错误。好像写的时候

a = [1,2,3]
def fun(a_list):
    a_list = a_list + [4]
    print(a_list)
fun(a)

>>>[1,2,3,4]

你得到 [1,2,3,4],所以它变成局部变量,但是当你写 arg += [4] 时,它表现为全局变量