zoukankan      html  css  js  c++  java
  • python变量的思考

       先看一段代码A

    1 x=12
    2 def foo():
    3      #print x
    4      x=x+1
    5      print x
    6 
    7 foo()

    执行上面的代码会输出什么呢?本人写python代码是还真心没注意过,一般也是把x作为

    foo()的参数。如果你执行上面的代码会报错:

    UnboundLocalError: local variable 'x' referenced before assignment

    不明白的话,看起来确实如此诡异!c语言可不会出现这种情况。如果没有第4行就会正常输出12。

    所以问题也就在第4行上。根据报错,大体原因应该知道了,那么我们改写一下上面的代码,代码B

    1 x=12
    2 print hex(id(x))
    3 def foo():
    4     x=1
    5     print hex(id(x))
    6 print x
    7 foo()

    本人运行输出的是:

    0x1d5d6a4

    12

    0x1d5d728

    看以看到id值并不相等,也就是foo函数的x是一个全新的变量,而且作用域仅在函数内。

    代码A中x=x+1并不是我们想当然等号右边的x是函数外部的x,这样也不是容易看明白的,

    我们使用dis模块反汇编一下。

    代码C:

    1 import dis
    2 x=12
    3 def foo():
    4     y=x+1
    5     print y
    6 
    7 dis.dis(foo)

    运行输出:

      4           0 LOAD_GLOBAL              0 (x)
                  3 LOAD_CONST               1 (1)
                  6 BINARY_ADD          
                  7 STORE_FAST               0 (y)
    
      5          10 LOAD_FAST                0 (y)
                 13 PRINT_ITEM          
                 14 PRINT_NEWLINE       
                 15 LOAD_CONST               0 (None)
                 18 RETURN_VALUE        

    代码D:

    1 import dis
    2 x=12
    3 def foo():
    4     x=x+1
    5     print x
    6 
    7 dis.dis(foo)

    运行输出:

      4           0 LOAD_FAST                0 (x)
                  3 LOAD_CONST               1 (1)
                  6 BINARY_ADD          
                  7 STORE_FAST               0 (x)
    
      5          10 LOAD_FAST                0 (x)
                 13 PRINT_ITEM          
                 14 PRINT_NEWLINE       
                 15 LOAD_CONST               0 (None)
                 18 RETURN_VALUE        

    比较一下代码D与代码C的不同,然后再看两段代码的输出。这里说一下,输出的第一列是代码的行号,

    第二列是指令在字节码的偏移,第三列指令,第四列示栈的索引序号。

    OK,我们看两段代码输出的第一行红色标记的指令,代码C是LOAD_GLOBAL指令,而代码D是LOAD_FAST。

    根据手册我们知道:

    LOAD_GLOBAL :载入全局co_names[namei]的值到栈上,namei就是此指令后面跟随的值(也就是输出的第四列);

    LOAD_FAST   :压入本地co_varnames[var_num]到栈上,var_num是此指令后面跟随的值。

        所以代码C是用全局的x加1,而代码D是利用本地的x加1,但是本地的x没有对应的索引值,必然就错了。

    一个变量在另一个作用域中不能做自加等类似的运算,对一个变量赋值相当于c语言中变量的声明并初始化。

    上面真正的字节码可以通过foo.func_code.co_code.encode('hex')获得,如代码D的输出:

    7c0000640100177d00007c0000474864000053

    7c指LOAD_FAST等等...

          再来看另一个例子:

    1 x=2
    2 print hex(id(x))
    3 def foo():
    4     x=2
    5     print hex(id(x))
    6 foo()

    输出:

    0x9551314
    0x9551314

    可以看出函数外的2与函数内的2是同一个。
    从索引数我们也能看出来:
     1 x=123456789
     2 #print hex(id(x))
     3 print sys.getrefcount(x),
     4 def foo():
     5     x=123456789
     6     #print hex(id(x))
     7     print sys.getrefcount(x),
     8     
     9 foo()
    10 print sys.getrefcount(x)
    输出:3 4 3
    在foo()内时增加了一为4,函数结束又变成了3.
    python要学的还很多......
  • 相关阅读:
    关于xcode中证书安装问题
    iOSOpenDev 安装流程
    openCV
    POJ2081(Recaman's Sequence)
    POJ1163(The Triangle)
    POJ3620(Avoid The Lakes)
    POJ1160(Post Office)
    POJ3177(Redundant Paths) or POJ3352(Road Construction)
    POJ1953(World Cup Noise)
    POJ1904(King's Quest)
  • 原文地址:https://www.cnblogs.com/wuchaofan/p/3494528.html
Copyright © 2011-2022 走看看