【问题标题】:why is python global scope affected by local scope operations?为什么 python 全局作用域会受到局部作用域操作的影响?
【发布时间】:2013-01-26 19:38:38
【问题描述】:

我认为传递给 python 函数的变量的更改保留在函数的本地范围内,而不是传递到全局范围内。但是当我写了一个测试脚本时:

#! /usr/bin/python
from numpy import *

def fun(box, var):
    box[0]=box[0]*4
    var=var*4
    return 0

ubox,x = array([1.]), 1.
print ubox,x
fun(ubox,x)
print ubox,x

输出是:

[myplay4]$ ./temp.py 
[ 1.] 1.0
[ 4.] 1.0

整数变量 x 不受函数内部操作的影响,但数组受。列表也会受到影响,但这只发生在对列表/数组切片而不是对单个元素进行操作时。

谁能解释一下为什么在这种情况下局部作用域会传递到全局作用域?

【问题讨论】:

    标签: python scope


    【解决方案1】:

    要意识到的重要一点是,当将对象传递给函数时,函数不能处理该对象的独立副本,而是处理同一个对象。因此,对对象的任何更改对外部都是可见的。

    您说对局部变量的更改仍然是局部的。这是真的,但它只适用于改变变量(即重新分配它们)。它不适用于改变变量指向的对象。

    在您的示例中,您重新分配了var,因此更改在外部不可见。但是,您正在改变 box (通过重新分配其元素之一)。这种变化在外部是可见的。如果您只是简单地重新分配 box 以引用不同的对象 (box = something),则该更改不会在外部可见。

    【讨论】:

    • 所以你是说整数不能改变?因为您所说的对整数无效。
    • @manu-fatto 打扰一下?我说过重新分配一个变量在外面是不可见的。这对整数完全有效。我还说过,变异对象在外面是可见的。这也适用于空洞事实的整数(即整数不能变异)。
    • 好吧,你是说整数是不可变的,而且......(快速检查后)你是对的!奇怪的是语法 n+=1 我认为它正在改变整数 n。
    • @manu-fatto += 的问题在于,它既可以是重新分配的快捷方式 (n = n + 1),也可以是变异操作,具体取决于给定类型是否定义了 __iadd__方法。对于整数,x += yx = x + y 的快捷方式。
    • 这很奇怪。但是,通过以下测试,我确信整数变量是引用:(10 is 5*2) == True, (1000 is 500*2) == False。
    【解决方案2】:

    在你的函数中

    def fun(box, var):
        box[0]=box[0]*4
        var=var*4
        return 0
    

    boxvar 都是本地的,更改它们不会更改它们在调用范围内的值。但是,这一行:

    box[0]=box[0]*4
    

    不改变box;它改变了box 所指的对象。如果那一行写成

    box = box[0]*4 + box[1:]
    

    那么调用范围内的box确实会保持不变。

    【讨论】:

    • 所以你是说 box 不是数组而是对数组的引用?
    • 没错。有问题的行并不是对局部变量的实际赋值。它是方法调用box.__setitem__(0,box[0]*4) 的真正语法糖。
    【解决方案3】:

    这与范围完全无关。

    你将一个对象传递给一个函数。在该函数内部,该对象发生了变异。关键是函数内部的变量和调用函数引用的是同一个对象,所以变化在外部是可见的。

    【讨论】:

      【解决方案4】:

      这不取决于范围。这取决于 Python 如何复制对象。在这方面,存在三种对象:标量、可变对象、不可变对象。

      标量是按值复制的,可变对象是按引用复制的,不可变对象可能是按引用复制的,但是由于您无法修改它们,因此没有任何含义。

      标量例如是所有数字类型。不可变的有:字符串和元组。可变的有:列表、字典和其他对象。

      【讨论】:

      • 文档中的什么地方说存在标量值并且它们是按值复制的?我从不想到 Python 中的“按值传递”。
      猜你喜欢
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 1970-01-01
      • 2014-03-20
      • 1970-01-01
      • 2015-08-22
      • 1970-01-01
      相关资源
      最近更新 更多