python函数对变量的作用域_如何改变函数中变量的作用域?Python

本问题已经有最佳答案,请猛点这里访问。

这似乎是一个非常愚蠢的问题,但我对Python中的作用域规则感到困惑。在下面的示例中,我将两个具有值的变量(x,y)发送到一个函数,该函数应该更改它们的值。当我打印结果时,变量没有改变。

def func1(x,y):

x=200

y=300

x=2

y=3

func1(x,y)

print x,y #prints 2,3

现在,如果这是C++,我将通过引用(ANP)将它们发送给该函数,从而能够改变它们的值。那么Python中的马是什么呢?更重要的是,当您将对象发送到函数时,实际会发生什么?python是否对这些对象进行了新的引用?

另外,python:如何通过引用传递变量?.

所有的python名称都是对对象的引用。函数参数仅绑定到传入的对象。如果没有内存位置,则在表达式中使用该名称时,总是将其取消引用。分配正在重新绑定,而不是更改原始内存位置。因此,x = 200正在创建一个新对象(int(200)并在x中存储对该对象的引用。

内部作用域具有从外部作用域访问变量的隐式权限,但需要显式权限才能从外部作用域修改变量。这大概和我说的一样简洁。

(cpython可以选择重用现有的int()对象,但这是一个实现细节)。

因此,虽然func1中的本地名称x和y开始绑定到与模块范围中的全局x和y名称相同的int()对象,但通过在函数内部分配它们,您只会反弹本地名称。全局名称仍然引用其原始值。

那么,如何使用函数来更改原始变量的引用呢?

@重新启动需要一些时间,然后读取顶部链接的重复线程。然后,如果你还是迷路了,用谷歌搜索global关键字。

把它们当作功能的一部分。当函数结束时,它的所有变量也将消失。

x=2

y=3

def func(x,y):

x=200

y=300

func(x,y) #inside this function, x=200 and y=300

#but by this line the function is over and those new values are discarded

print(x,y) #so this is looking at the outer scope again

如果您希望函数按照您编写的方式修改值,那么可以使用global,但这是非常糟糕的做法。

def func(x,y):

global x #these tell the function to look at the outer scope

global y #and use those references to x and y, not the inner scope

x=200

y=300

func(x,y)

print(x,y) #prints 200 300

问题在于,在最好的情况下调试是一场噩梦,而在最坏的情况下调试是完全不可能的。像这样的事情在函数中通常被称为"副作用"——设置一个不需要设置的值,如果不显式返回它,那么这样做是一件坏事。通常,您应该编写的修改项目的唯一函数是对象方法(比如[].append()修改列表,因为返回一个新的列表是愚蠢的!)

这样做的正确方法是使用返回值。尝试一下

def func(x,y):

x = x+200 #this can be written x += 200

y = y+300 #as above: y += 300

return (x,y) #returns a tuple (x,y)

x = 2

y = 3

func(x,y) # returns (202, 303)

print(x,y) #prints 2 3

为什么不起作用?好吧,因为你从来没有告诉程序对这个tuple(202, 303)做任何事情,只是为了计算它。我们现在分配吧

#func as defined above

x=2 ; y=3

x,y = func(x,y) #this unpacks the tuple (202,303) into two values and x and y

print(x,y) #prints 202 303

使用函数时,如何更改x,y?

在函数结束时显式调用return x, y,然后调用x, y = func(x, y)。

@重新启动:你不能;你正在传递的对象是不可变的,因此不可能更改它们,而且你不能仅仅根据传入的内容重新绑定外部作用域中的名称。(您可以使用global关键字在全局重新绑定名称x和y,但无论传入的对象是什么,都会发生这种情况;在这种情况下,func(a,b)只会修改x和y……

我现在明白了。谢谢

@Reboot_我用不同的方法进行了大量的编辑。试试看。如果可能的话,不要使用global,这是一个糟糕的实践,并且会使调试过程避开大力神。

我非常感谢你的回答。这使我明白了整个问题

@重新启动对我来说,它有助于像构建器一样思考函数。你不给你的建设者数字2和3,让他改变这些数字,你就给建设者蓝图。""嘿,伙计,"你可能会说,"我想让你给我做一些看起来像这里的东西,但不同的东西。"然后当他做完后,建筑商回来说,"来吧,伙计,这是我做的一个新东西,看起来像你给我看的一样!"

与对象方法相反,在对象方法中,你告诉一个对象(一个列表,或者你做的东西,等等)"嘿,伙计,我知道作为一个对象你很酷,但是我需要你继续为我做些事情。"然后对象就可以自己操作——它不需要构建一个新的自身副本来实现这一点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值