为什么你可以改变不可变的全球

时间:2015-11-07 14:28:16

标签: python function python-2.7 global immutability

有人可以向我解释为什么我可以更改不可变变量,如果它在Python中是全局的吗?我不明白为什么这在全球状态下是允许的,而在其他地方都不允许。我最近开始学习编程,但我还是没有得到它。示例如下。

class Ddata():
    def __init__(self, iw, ih, fw, fh):
        self.iw = iw
        self.ih = ih
        self.fw = fw
        self.fh = fh

x = Ddata(1784, 366, 160, 180)

s_h = 0
s_w = 0
c_f = 20

def sp(x, cf, sw, sh):
    sw = x.fw * cf
    print sw
    if sw > x.iw:
        sw -= x.iw
        print sw
        sh = (sh + x.fh) + 4

sp(x, c_f, s_w, s_h)

print s_w
print s_h

print "----"  

def sp_global():
    global s_w
    global s_h
    global c_f
    global x
    s_w = x.fw * c_f
    print s_w
    if s_w > x.iw:
        s_w -= x.iw
        print s_w
        s_h = (s_h + x.fh) + 4

sp_global()

print s_w
print s_h

4 个答案:

答案 0 :(得分:2)

我认为你混淆全局变量和函数同名的局部变量 考虑例如

int_data = 15

def some_func():
    int_data = 10   # This now creates a new local variable of same name instead of updating global variable
    print int_data  # prints local variable with value 10

some_func()

这是因为在python中,当任何值分配给尚未可用的变量时,会创建一个新变量 要避免创建新变量并更新全局变量,必须使用关键字global

明确提及

答案 1 :(得分:2)

一些核心事项:

  • 根据他们的行为命名您的变量,没有人可以阅读您的代码
  • 请勿使用global。它从来没有必要,只是不好的做法,并会让你很难概述你的代码。我知道你这样做是为了表明事情,但仍然只是提示;)

  • 编辑:如果不清楚:实例变量(对象/类的变量)不是不可变的;)

关于不可变对象的事情:

不变性的概念不是你在这里看到的。不可变变量是指在创建变量后无法更改的变量。一个例子是元组,因为你之后无法改变它们的组件。

您在此处看到的只是名称范围。

如果更改函数内的变量,则会在自己的本地名称范围内更改它们。虽然它们不会改变给予它们的东西,因为这会产生很大的问题(考虑一个变量,如给一个函数的名称,如果名字应该给你第一个字母。如果函数会自动更改名称,程序将“忘记“它,之后只有第一个字母”。 如果要使用函数外部函数的结果返回它们。如果你想使用类的概念,其中函数(对于它们被称为方法的类)改变对象(类的)的属性(变量),那么你必须将这些函数声明为类的方法。 在您的示例中,您将按照以下方式调用它们:x.sp(...)

有关类(面向对象编程)概念的更多信息,请在网上搜索有很多很好的解释和示例。它是编程的核心概念,对学习非常有用!

修改 由于这似乎并不清楚,我编辑了两种可能的代码:

class Ddata():
    def __init__(self, iw, ih, fw, fh):
        self.iw = iw
        self.ih = ih
        self.fw = fw
        self.fh = fh

        self.sh = 0
        self.sw = 0

    def sp(self, cf, sw, sh):
        sw = self.fw * cf
        print (sw)
        if sw > self.iw:
            sw -= self.iw
            print (sw)
            sh = (sh + self.fh) + 4

        self.sh = sh
        self.sw = sw

        return (self.sw, self.sh)



x = Ddata(1784, 366, 160, 180)

s_h = 0
s_w = 0
c_f = 20

result_of_sp = x.sp(c_f, s_w, s_h) #result is a tuple where we store two values


print (result_of_sp[0])
print (result_of_sp[1])

print ("----")  

x = Ddata(1784, 366, 160, 180)

def sp_global():
    global s_w
    global s_h
    global c_f
    global x
    s_w = x.fw * c_f
    print (s_w)
    if s_w > x.iw:
        s_w -= x.iw
        print (s_w)
        s_h = (s_h + x.fh) + 4

sp_global()

print (s_w)
print (s_h)

现在两个方法都具有与返回函数结果相同的效果,然后将其存储在包含两个值的变量中,作为我们稍后可以引用的元组。另外,我让函数将sh和sw存储的值保存在Objects自己的变量中(用self.variable标记)。所以你也可以用x.sw和x.sh来引用它们。

该函数现在是Ddata的一个方法,并且对它自己的对象(由(self,...,...,...)声明方法args。这样你可以将值存储在你的名字中类的范围(对象。或者只是返回它。你的选择。

答案 2 :(得分:1)

Python中不存在不可变变量,所有变量都可以在您有权访问的任何范围内更改。

可变性是指变量是否可以变异;例如,您可以更改列表的内容,但不能更改元组。这些都不是指重新分配。

答案 3 :(得分:0)

当您处理不可变对象时,您无法更改其中的数据。例如,以下内容无效,因为元组类型是不可变的:

somevar = (1, 2)
somevar[0] = 3  # boom!

更改不可变数据中的数据的唯一方法是使用新数据创建新对象并将其重新分配给变量。如果没有任何东西指向对象,则原始对象将由垃圾收集器从内存中清除。

当您将变量传递给函数时,如果您可以“编辑”它(即:它是可变的),则外部作用域将看到更改,因为您没有更改变量的内存地址:

def edit(l):
    l[0] = 3

somelist = [1, 2, 3]
edit(somelist)
print somelist  # [3, 2, 3]
在这种情况下,

'l'是一个指向全局列表的变量,您正在修改其中的数据;你没有改变内存地址。

不同于:

def edit(l):
    l = [3, 2, 3]

somelist = [1, 2, 3]
edit(somelist)
print somelist  # [1, 2, 3]

在这种情况下,'l'指向的内存地址会随'='语句而变化。但是因为你处于一个函数的范围内,某些列表仍然存在,仍然指向'l'的旧位置。

当您使用'global'时,您不会获得函数范围的变量,就像您将其作为参数接收一样。相反,你正在使用实际的全局变量,所以如果你重新分配它,你实际上是在全局级别而不是在函数级别上使用变量。

somelist = [1, 2, 3]

def edit():
    global somelist
    somelist = [3, 2, 3]

edit()
print somelist  # [3, 2, 3]

- 编辑 -

在回答你的问题时,以下是如何使用函数更改全局不可变(无用的示例,但您可以看到机制):

def edit(l):
    val1, val2, val3 = l
    return (3, val2, val3)

sometuple = (1, 2, 3)
sometuple = edit(sometuple)
print sometuple  # (3, 2, 3)

我建议阅读:Short Description of the Scoping Rules?