本文主要总结python中的全局变量、局部变量和函数调用时的可变对象的使用:

1、关于全局变量和局部变量

(1)如果函数内无global关键字,优先读取局部变量,无局部变量则读取全局变量,不能对全局变量重新赋值。

name = 'jack'

def change_name():
    name = 'john'
    print(name)

change_name()
print(name)

输出:

john
jack

(2)如果函数中有global关键字,可以读取或者重新给全局变量赋值。

name = 'jack'

def change_name():
    global name    # 修改全局变量
    name = 'john'
    print(name)

change_name()
print(name)

输出:

john
john

(3)修改全局变量和修改上一级变量
修改全局变量:

name = 'Jack'

def one():
    name = 'Tom'

    def two():
        global name
        name = 'Jarry'

    two()
    print(name)

print(name)
one()
print(name)

输出:

Jack
Tom
Jarry

修改上一级变量:

name = 'Jack'

def one():
    name = 'Tom'

    def two():
        nonlocal name   #修改上一级变量
        name = 'Jarry'

    two()
    print(name)

print(name)
one()
print(name)

输出:

Jack
Jarry
Jack
2、关于函数调用时的可变对象的使用:

(1)对于可变对象可以对内部元素进行操作,相当于传引用

name = ['jack', 'john']

def change_name():
    name.append('tom')
    print(name)

change_name()
print(name)

输出:

['jack', 'john', 'tom']
['jack', 'john', 'tom']

(2)递归程序中的使用

首先,看一下在C++中,如何在递归调用中使用全局变量或者函数参数:

在编写递归函数时,我们可以选择使用全局变量,也可以选择使用函数参数。这两者的差别在于:

  • 使用全局变量:递归结束后必须对该变量修改,恢复原值;
  • 使用函数参数:因为递归调用函数时,实际上,从内存分布上看,每一层调用都保存了该层函数的参数,因此递归返回上层时,不会影响原参数值。

从一个题目看下两者的区别:

题目:求二叉树中和为某一值的路径。

使用全局变量:

int currentSum = 0;  
vector<Node *> path;

void traverse(Node *root, int expectedNum) {
    if(root==NULL) return;

    currentSum += root->value;  
    path.push_back(root);  
    
    // 如果是叶节点,并且路径上结点的和等于输入的值  
    if(root->left == NULL && root->right == NULL) {  
        if(currentSum == expectedNum) {  
            show(path);  
            cout << currentSum <<endl;  
        }  
    }  

    traverse(root->left, expectedNum);  
    traverse(root->right, expectedNum);  
	
	// 必须恢复,所有函数调用使用同一个值
    currentSum -= root->value;
    path.pop_back();
}

使用普通的函数参数:

void traverse(Node *root, int currentSum, vector<Node *> path, int expectedNum) {
    if(root==NULL) return;

    currentSum += root->value;  
    path.push_back(root);  
    
    //如果是叶节点,并且路径上结点的和等于输入的值  
    if(root->left == NULL && root->right == NULL) {  
        if(currentSum == expectedNum) {  
            show(path);  
            cout << currentSum <<endl;  
        }  
    }  

    traverse(root->left, currentSum, path, expectedNum);  
    traverse(root->right, currentSum, path, expectedNum);  

    // 不必恢复  currentSum, path, 各函数调用层独立使用  
}

python中使用可变对象:

class TreeNode:
    def init(self, x):
        self.val = x
        self.left = None
        self.right = None
        
class Solution:
    def __init(self):
        self.result = []
        
    def find_path(self, node, sum):
        """输入一个二叉树和一个整数,打印出二叉树中节点值的和等于输入整数所有的路径"""
        if node is None:
            return

        stack = []
        path_sum = 0

        self.find_sum_core(node, sum, stack, path_sum)

        print(stack)
        print(path_sum)

    def find_sum_core(self, node, sum, stack, path_sum):
        stack.append(node.val)    # 相当于全局变量,需手动恢复现场
        path_sum += node.val      # 局部变量,递归自动保护现场

        if node.left is None and node.right is None:
            if path_sum == sum:
                self.result.append(copy.deepcopy(stack))

        if node.left is not None:
            self.find_sum_core(node.left, sum, stack, path_sum)

        if node.right is not None:
            self.find_sum_core(node.right, sum, stack, path_sum)
		 
		 # 返回上层前要恢复现场
        stack.pop(-1)

if __name__ == '__main__':
    node1 = TreeNode(1)
    node2 = TreeNode(2)
    node3 = TreeNode(3)
    node4 = TreeNode(4)
    node5 = TreeNode(7)
    node6 = TreeNode(6)
    node7 = TreeNode(7)

    node1.left = node2
    node1.right = node3
    node2.left = node4
    node2.right = node5
    node3.left = node6
    node3.right = node7

    print("****** Test the path of sum is target: ******")
    S = Solution()
    S.find_path(node1, 10)
    print(S.result)

输出:

****** Test the path of sum is target: ******
[[1, 2, 7], [1, 3, 6]]