作者mantour (朱子)
看板Python
标题Re: [问题] 关於class 内变数的问题
时间Thu Jan 22 13:27:48 2009
※ 引述《gardenest (股海寻灯)》之铭言:
: 因为一样是变数的问题,所以我直接回这个标题。
: 1、
: a = 1
: class testing:
: def test(self):
: a = 0
: print a
: def test2(self):
: print a
: obj = testing()
: obj.test()
: obj.test2()
: print a
: ----------output
: 0
: 1
: 1
: -----------
: 看起来像是最上面第一行a的值并没有被test()改成0,所以後面印出来的还是1。
: 2、
: 但是当我将a改成list的型态时,它似乎会被改变了。
: a = [1]
: class testing:
: def test(self):
: a.append(2)
: print a
: def test2(self):
: print a
: obj = testing()
: obj.test()
: obj.test2()
: print a
: ---------output
: [1,2]
: [1,2]
: [1,2]
: ---------
: 看起来a在test()里被改变了。
: 以上这2个例子让我感到很困惑,一个会被改,一个不会被改,
: 想请问为什麽会有这样子的差异呢?
以下是我目前的理解,如果有什麽错的地方还请各位指正^^
先简化一下问题
def function1():
a=1
print a
return
def function2():
print a
return
a=0
function1()
function2()
print a
结果是
1
0
0
因为python没有变数宣告
所以当你在函式内assign一个值给某个变数时
它就当作在这个函式内产生一个区域变数
所以function1的a就被当成是区域变数,後面的print就是print区域变数的值
而function2内没有名为a的区域变数,所以它就会去外面找最近的a来print
同样的
def function1():
a=[1]
print a
return
def function2():
print a
return
a=[0]
function1()
function2()
print a
这样会得到
[1]
[0]
[0]
还有一个有趣的行为是
def function1():
print a
a=1
print a
return
a=0
function1()
它会回应: UnboundLocalError: local variable 'a' referenced before assignment
即是说,只要函式中任何一个位置assign了a的值,a就会在整个函式中被当成
区域变数(不管是assign前还是assign後),所以你就不能在assign之前对a取值
但是如果你在函数中调用变数的method的话,因为函式中没有同名的区域变数
所以它就会去外面找最近的同名变数
比如说
def function1():
a[0]=1
print a
return
a=[0]
function1()
print a
就会得到
[1]
[1]
因为在function1中 读到a[0]=1这一行时,它会去找function1中有没有指定'a'为区域
变数,没有的话就会去外面找最近的a来用罗
这个特性有时可以玩一些tricks
例如:
counter=0
def function():
counter=counter+1
return counter
function()
它会说
UnboundLocalError: local variable 'counter' referenced before assignment
因为没有变数宣告的机制,所以它把counter当作是区域变数了
一个变通的方法就是使用global statement
counter=0
def function():
global counter
counter=counter+1
return counter
function()
function()
function()
就会得到
1
2
3
...
在这边global counter这一行的意思就是告诉interpreter说在这边的'counter'
要用的是"最外面"的counter
然而你也可以用前面所说的特性来达到同样的效果,例如:
counter=[0]
def function():
counter[0]=counter[0]+1
return counter[0]
function()
function()
function()
此外,global的使用还是有一些限制
例如:
def geniter():
c=0
def iter():
global c
c=c+1
return c
return iter
iter=geniter()
iter()
它又会跟你说:
NameError: global name 'c' is not defined
因为你使用global statement的时候
它会去「最外层」找全域变数来用
所以又会跟你说找不到…
但是使用前面的技巧,就还是可以达成目的:
def geniter():
c=[0]
def iter():
c[0]=c[0]+1
return c[0]
return iter
iter1=geniter()
iter2=geniter()
iter1()
iter1()
iter1()
iter2()
iter2()
iter2()
就会得到
1
2
3
1
2
3
一个新闻是在python 3.0中多了 nonlocal statement可以用来表示
我要使用「上一层」的变数
所以应该就可以写成
def generator():
c=0
def f():
nonlocal c
c=c+1
return c
return f
感觉上会变得比较直觉(没有装3.0所以没试过)
总之没有宣告变数的机制其实还是有一些不方便的地方啦
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.112.213.158
※ 编辑: mantour 来自: 140.112.213.158 (01/22 13:31)
※ 编辑: mantour 来自: 140.112.213.158 (01/22 13:33)
1F:推 aquarianboy:补充一下,第一个范例的结果应该是1 0 0 印了三次 :) 01/22 13:59
谢谢 已改^^
※ 编辑: mantour 来自: 140.112.213.158 (01/22 14:01)
2F:推 gardenest:感谢man大的解答,非常详细,这个问题困惑我好久,终於 01/22 15:38
3F:→ gardenest:决了^__^ 01/22 15:38
4F:→ gardenest:解决了^__^ 01/22 15:39