Python 不可变的函数参数
我正在尝试理解Python的核心概念,看到了一篇不错的文章,讲的是如何将参数的引用传递给一个对象。比如说:
def add_to_list(list_to_add, value):
list_to_add.append(value)
这样做可以改变原来的list_to_add参数,而;
def change_list(list_to_add):
list_to_add = [1, 2, 3, 5]
这样做就不会有任何变化。
我现在正在写一个基本的链表打印函数,简单来说就是:
class Node:
def __init__(self, val, next=None):
self.val = val
self.next = next
root = Node(2, Node(3, Node(4, Node(5, Node(6)))))
def print_list(root):
while root:
print root.val,
root = root.next
print ''
你们猜得没错,它并没有改变根节点的值。现在我想问的是这是为什么呢。是因为Python的类是不可变的吗?
2 个回答
1
这很简单:
obj.do_something()
这个操作会对传入的对象进行处理,可能会修改它(比如用 list_to_add.append()
来添加元素),而
obj = something_other
则会丢掉对旧对象的引用,使用一个新的对象。
对一个对象的修改(当然)会被“其他”使用这个对象的人看到,而重新赋值只会影响到被重新定义的地方。
4
Python的类并不是不可改变的。你可以随意修改它们(当然有一些特殊情况,比如扩展类型或者slots)。
不过在这里,你定义了一个模块级别的(全局)变量叫做root,然后在print_list函数里又定义了一个同名的参数root。
当你调用print_list(root)并给root赋值时,这并不会改变模块级别的全局变量!
如果你想要改变全局变量(虽然其实不应该这样做,这又是另一个关于避免使用全局变量的讨论),你需要在print_list里声明root为全局变量。
def print_list():
global root
...
这样的话你就不需要这个参数了。
再说一遍:千万不要这样做!!!
如果你使用像pylint这样的工具来检查你的代码,它应该会警告你参数名“root”会覆盖模块级别的全局变量“root”。