1. __call__、__getattr__
1 class B():
2 def __call__(self, name):
3 return getattr(self, name)
4
5 def a(self, text):
6 print 'a' + text
7
8 def b(self, text):
9 print 'b' + text
10
11 class A():
12 def __getattr__(self, name):
13 bb = B()
14 return bb(name)
15
16 aa = A()
17 aa.a('aaaa')
18 aa.b('bbbb')
运行结果:
aaaaa
bbbbb
解释:
16行生成A的一个对象aa,17行来调用aa的方法a,由于A中没有定义方法a(依实例属性->类属性->__getattribute__()->__getattr__()的顺序查找),所以调用A的方法__getattr__得到bb(a),由于bb是类B的一个实例,所以调用bb.__call__(a)得到bb.a,加上传递过来的参数'aaaa',即调用bb.a('aaaa')得到aaaaa。
附上两个函数的解释:
__getattr__( self, name):
Called when an attribute lookup has not found the attribute in the usual places.
__call__( self[, args...])
Called when the instance is "called" as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x.__call__(arg1, arg2, ...).
现在应该很容易理解下面的这段程序为什么得到的结果是6 8了吧~~~
1 class Prod:
2 def __init__(self, value):
3 self.value = value
4
5 def __call__(self, other):
6 return self.value * other
7
8 x = Prod(2)
9 print x(3)
10 print x(4)
2. 外部变量能否改变
注:此部分只是依实验结果猜测的结论,没有深入研究
先看这段:
1 def foo(x):
2 def tom(y):
3 print x + y
4 return tom
5
6 cc = foo(100)
7 cc(200)
运行结果: 300
很好理解:每6行时已经把100存入foo的locals()里了,第7行时tom的locals()中x=100,y=200,相加后为300
问题:在tom中能否改变x的值?
1 def foo(x):
2 def tom(y):
3 x += 1
4 print x + y
5 return tom
6
7 cc = foo(100)
8 cc(200)
运行后出现错误:
Traceback (most recent call last):
File "2.py", line 8, in <module>
cc(200)
File "2.py", line 3, in tom
x += 1
UnboundLocalError: local variable 'x' referenced before assignment
未绑定局部变量:引用局部变量'x'之前没有赋值
原来在内部函数tom中,x被Python解释器看成是内部函数tom中的局部变量,并不是我们认为的外部(函数foo中的)变量。即在tom中,x只是一个尚未赋值的变量--尽管与外部的x同名,因此不能执行加法计算。
再看:
1 def foo(x):
2 xs = [x]
3 def tom(y):
4 xs[0] += 1
5 print xs[0] + y
6 return tom
7
8 cc = foo(100)
9 cc(200)
10 cc(200)
运行结果:
301
302
可以看出此时外部变量对于内部的函数而言是共享的
不是说外部变量不能改变吗,这里怎么可以改变xs呢。看好了,这里只是改变xs里的值,xs的地址并没有改变。试试:
>>> xs = [100]
>>> xs.__str__
<method-wrapper '__str__' of list object at 0xb74054ac>
>>> xs[0] += 1
>>> xs.__str__
<method-wrapper '__str__' of list object at 0xb74054ac>
再看看上面出错的那种:
>>> x = 100
>>> x.__str__
<method-wrapper '__str__' of int object at 0x815d114>
>>> x += 1
>>> x.__str__
<method-wrapper '__str__' of int object at 0x815d108>
x的地址改变了!
这说明外部函数传给内部函数的只是地址,这个地址指向的值可以变,但这个值不允许改变。
注:Python3.0增加了一个新关键字--nonlocal,用于在嵌套函数中访问外部变量。