Über den Umfang von Python-Variablen
给我你的怀抱
给我你的怀抱 2017-05-18 10:53:10
0
3
731

Es gibt so eine Funktion:

def outside():
    x=[]
    print(id(x))
    def inside():
        print(id(x))
        x[:]=[1,2,3]
        print(id(x))
    inside()
    print(id(x))
    print(x)

Nach dem Anruf ist kein Problem aufgetreten, Ausgabe:
140560473157960
140560473157960
140560473157960
140560473157960
[1, 2, 3]

Aber ersetzen Sie das x darin durch eine Zeichenfolge, wie folgt:

def outside():
    x='outside'
    print(id(x))
    def inside():
        print(id(x))
        x='inside'
        print(id(x))
    inside()
    print(id(x))
    print(x)

Wenn der Anruf erneut erfolgt, wird daraus:

140560473762872
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in outside
  File "<stdin>", line 5, in inside
UnboundLocalError: local variable 'x' referenced before assignment
  • Wurde die inside函数里,为什么x不指向原来的'outside'Zeichenfolge gemäß den Regeln zu diesem Zeitpunkt eingegeben?

  • Sollten undefinierte Variablen nicht NameError erzeugen?

  • Ich dachte ursprünglich, dass Strings und Listen Zeigern in C ähneln, aber es scheint, dass dies jetzt nicht der Fall ist. Wenn möglich, hoffe ich, eine Einführung in diesen Punkt zu geben, danke.

给我你的怀抱
给我你的怀抱

Antworte allen(3)
我想大声告诉你

从易到难一个个回答, 因为是个人愚见, 所以如果有大神看到说得不正确, 希望能够指出
类似C中的指针: 这个是正确的, 因为在py里面, 几乎所有的事物都是对象, 就连变量赋值, 也是先生成对象, 再让变量指向这个对象,而对象还分可变对象不可变对象, 在对可变对象操作时, 是会影响到其他指向这个对象的变量, 例如:

o = [1, 2, 3, 4]
b = o
print id(o)
print id(b)
b[1] = 123123
print b
print o
输出:
39946376
39946376
[1, 123123, 3, 4]
[1, 123123, 3, 4]  # o指向的列表也被改变

而对于不可变对象, 是直接就放弃旧的对象, 而指向新的对象, 例如:

s = '123123'
print id(s)
s = '32131'
print id(s)


# 输出:
41392768
41392808

所以你在操作python对象时, 需要谨记该对象是属于哪种类型, 你的操作又会不会因为这些特性而失败或者没达到自己想要的效果.

未定义的变量: python在查找变量时, 将遵循LEGB的顺序, 只有都查找完毕还是没找到的情况下, 才会触发NameError异常, 这个可以参考我的一篇博文: Python: 作用域(scope) 和 LEGB

UnboundLocalError: 这个问题是最常见, 也是最难解释的, 因为我们总是相当然地觉得, 它必定就会根据ELGB的顺序去查到变量;其实我们的理解并没错误, 只是我们忽略了一点:赋值语句,如果函数代码段没有赋值语句, 那么这个问题是不会出现, 但为什么出现赋值语句就会报错呢? 这和python的作用域有关, 在上面那篇文章提到, python作用域并不是动态的,而是静态的, 从脚本文件的缩进, 就能看出来的, 所以在代码:

 x='outside'
    print(id(x))
    def inside():
        print(id(x))
        x='inside'
        print(id(x))

inside中, 已经有了赋值语句, 所以对于x,他已经不会从enclosing 或者global甚至bulitin里面去查找, 它已经被认定在local域了, 只是这个值并没有和真正的对象'inside'建立起绑定关系, 因为代码没有运行到真正的赋值语句, 所以, 会触发这个UnboundLocalError. 而为什么那个列表会可以那样做, 因为他们两个是完全不同的操作, 同样都是print(id(x))list的操作字节码是LOAD_DEREF, 而字符串的操作字节码是LOAD_FAST, 而x[:]=[1,2,3]/x='inside'分别对应的字节码又是STORE_SLICE+3STORE_FAST, 前者是在原来的基础上修改, 而后者是重新指向新的对象, 而这两种方式的区别, 决定了,它们在构建函数时, 以怎样的形式存放x, 这个就涉及到python函数构建的原理了, 有兴趣可以看看源码中的object/ceval.c源码, 这是虚拟机运行的原理, 关于这个问题可以简单看我另一篇文章, 比较简单将UnboundLocalError: 说下那神奇的 UnboundLocalError: local variable x referenced before assignment

某草草

你在inside函数里面重新赋值了新的变量x,两个x的作用域是不相同的。
而导致UnboundLocalError,是因为你在inside的作用域里面,打印了一个没有初始化的变量。
具体看这个解释:
https://docs.python.org/2/faq...

洪涛

基本上Lin_R已经说的很清楚了。
outside函数与inside函数,他们的域是不同的。由于你在inside函数中对x进行了赋值,当在inside函数中使用变量x时,此时x就被认定是在inside的local域中。此时的x是不会使用其他域中的值的。所以在print(x)时,由于x没有初始化的值,因此出错。虽然在c中可以使用已定义而未赋值的变量,但是python不允许这种情况。

在python3中,有一个nonlocal语句可以解决这个问题。

def outside():
    x='outside'
    print(id(x))
    def inside():
        nonlocal x
        print(id(x))
        x='inside'
        print(id(x))
    inside()
    print(id(x))
    print(x)

注意,此时使用global语句是不行的,因为在global域内没有x这个变量。

Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage