Python参数传递与变量作用域:在回溯算法编程时的重要体现

Python参数传递

  和其他语言不一样,传递参数的时候,python不允许程序员选择采用传值还是传引用。Python参数传递采用的是“传对象引用”的方式,这种方式相当于传值和传引用的一种综合:

  • 如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值,相当于通过“传引用”来传递对象;
  • 如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象,相当于通过“传值’来传递对象。

Python变量作用域

  Python变量的作用域大概分为以下四类:

  • L(local) 局部作用域
  • E(Enclosing) 闭包函数外的函数中
  • G(Global) 全局作用域
  • B(Built-in) 内建作用域

访问顺序是: L → E → G → B L\rightarrow E\rightarrow G\rightarrow B LEGB,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

x = 3  # 内建作用域
g_count = 0  # 全局作用域
def outer():
    o_count = 1  # 闭包函数外的函数中
    def inner():
        i_count = 2  # 局部作用域

  在Python中,模块(module),类(class)、函数(def、lambda)会产生新的作用域,其他代码块是不会产生作用域的,也就是说,类似条件判断(if……else)、循环语句(for x in data)、异常捕捉(try…catch)等的变量是可以全局使用的

应用

修改函数内的变量

  全局变量是指在函数外的变量,可以在程序全局使用,局部变量是指定义在函数内的变量,只能在函数内被声明使用。
  若内部作用域的想要修改外部作用域的变量,就要使用global关键字:

x=1
def func():
	global x
	x+=2
func()
print(x)

输出

3

错误示例:

x=1
def func(x):
	x+=2
func(x)
print(x)

输出

1

  nonlocal 关键字的使用方法和global关键字类似,修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量:

def outer():
    num = 20
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 10
        print(num)
    inner()
    print(num)
outer()

输出:

10
10

回溯

  • 可变对象(比如字典或者列表)通过“传引用”来传递对象,因此在结算时要做一个拷贝,在回溯时要重置现场;
  • 不可变对象(比如数字、字符或者元组)通过“传值’来传递对象,每次都用一个新的,因此无需状态重置。

  使用回溯算法时,有时候需要一个数字变量ans存储所有可能的结果数量,这个变量定义在回溯函数外,并且需要在函数内修改。

  下面以《剑指offer》46. 把数字翻译成字符串为例,说明使用Python编程回溯算法时,搞懂参数传递与变量作用域的重要性。

题目描述:

  给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

回溯算法思路:

  • 由于对应字母的数字在0~25之间,从头开始遍历,每一步面临选择:一位数代表的字母OR两位数代表的字母,即向前移动一位还是两位;
  • 向前移动两位的前提是,这个两位数在10~25之间。

正确程序一:

nums=[5,0,9]
n=len(nums)
ans=0#内建变量
def backtrack(i):
    global ans#声明为全局变量
    if i>=n:
        ans+=1
        return
    backtrack(i+1)
    if i+1<n and 10<=nums[i]*10+nums[i+1]<26:
        backtrack(i+2)
        
backtrack(0)
print(ans)

正确程序二:

def translateNum(num):
    nums=[int(_) for _ in str(num)]
    n=len(nums)
    ans=0
    def backtrack(i):
        nonlocal ans
        if i>=n:
            ans+=1
            return
        backtrack(i+1)
        if i+1<n and 10<=nums[i]*10+nums[i+1]<26:
            backtrack(i+2)
        
    backtrack(0)
    return ans

translateNum(509)

错误程序一:

def translateNum(num):
    nums=[int(_) for _ in str(num)]
    n=len(nums)
    ans=0
    def backtrack(i):
        if i>=n:
            ans+=1
            return
        backtrack(i+1)
        if i+1<n and 10<=nums[i]*10+nums[i+1]<26:
            backtrack(i+2)
        
    backtrack(0)
    return ans

translateNum(509)

错误原因:

local variable 'ans' referenced before assignment

错误程序二:
backtrack(i,ans)传入ans是“传值”,函数内部ans+=1重新创建了一个同名变量,其作用域仅在函数内部,最后返回的是外层函数的变量ans,所以无论输入什么,结果都是0.

def translateNum(num):
    nums=[int(_) for _ in str(num)]
    n=len(nums)
    ans=0
    def backtrack(i,ans):
        if i>=n:
            ans+=1
            return
        backtrack(i+1,ans)
        if i+1<n and 10<=nums[i]*10+nums[i+1]<26:
            backtrack(i+2,ans)
        
    backtrack(0,ans)
    return ans

translateNum(509)

python在函数中改变外部变量
python变量作用域

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值