nonlocal作为关键字在Python3.0中被引入
nonlocal
关键字,和global
一样用来标识变量所在的命名空间,用在嵌套函数中,表示外层
使用nonlocal
关键字可以修改外层函数中变量的值
>>> def outer():
a = 1
def inner():
a += 1
print("Inner",a)
inner()
print("Outer",a)
>>> outer()
UnboundLocalError: local variable 'a' referenced before
assignment
>>> def outer():
a = 1
def inner():
nonlocal a
a += 1
print("Inner",a)
inner()
>>> outer()
Inner 2
Outer 2
>>> a = 1
>>> def outer():
global a
a += 1
def inner():
a += 1
print("Inner",a)
inner()
print("Outer",a)
>>> outer()
Inner 3
Outer 3
>>> class Counter(object):
def __init__(start):
self.state = start
def __call__(self, label):
print(label, self.state)
self.state += 1
>>> c1 = Counter(1)
>>> c1("Apple")
Apple 1
>>> c1("Pear")
pear 2
>>> c2 = Counter(100)
>>> c2("Peach")
Peach 100
>>> def tester():
def nested():
print(label,nested.state)
nested.state += 1
nested.state = start
return nested
>>> f= tester(0)
>>> f('span')
span 0
Python语言的一大特色就是允许定义嵌套函数:定义在函数内的函数,可以访问其外层函数的变量,前面讲过使用nonlocal
关键字还可以对其进行修改
闭包的定义:闭包也称词法闭包——如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure),这里说的作用域就是nonlocal;通俗来讲,闭包就是把一个函数(方法)作为一个变量来使用
使用嵌套函数可以很容易的实现闭包功能
#!/usr/bin/env python3
#Filename: counter.py
#Function: Use closure to create a counter function that can count the number.
>>> def counter():
i = 0
def nested():
nonlocal i
i += 1
return i
return nested
>>> c = counter()
>>> print(c(),c(),c(),end=" ")
1 2 3
>>> d = counter()
>>> print(d(),d(),d(),end=" ")
1 2 3
装饰器(decorator)可以通过闭包实现
把被装饰得函数传入装饰器以获得装饰
#Function: The class that to be decorated.
>>>class Coordinate(object):
... def __init__(self, x, y):
self.x = x
self.y = y
... def __repr__(self):
return "Coord: "+str(self.__dict__)
>>> def add(a, b):
return Coordinate(a.x + b.x, a.y + b.y)
>>> def sub(a, b):
return Coordinate(a.x - b.x, a.y - b.y)
>>> one = Coordinate(100, 200)
>>> two = Coordinate(300, 400)
>>> add(one, two)
Coord: {'y': 400, 'x': 400}
>>> sub(one, two)
Coord: {'y': -200, 'x': -200} #这里出现了负值,我们可以通过装饰器修饰之使它恒为正数,详见后文
#Function: As a decorator, to insure that the results of add() and sub() are always positive.
>>> def wrapper(func):
def checker(a, b):
if a.x < 0 or a.y < 0:
a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
if b.x < 0 or b.y <0
b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
if ret.x < 0 or ret.y < 0:
ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
return ret
return checker
>>> add = wrapper(add)
>>> sub = wrapper(sub)
>>> add(one, two)
Coord: {'y': 400, 'x': 400}
>>> sub(one, two)
Coord: {'y': 0, 'x': 0}
Python2.4中引入了一个符号@
表示装饰器,是一个方便的语法糖
>>> @wrapper
... def add(a, b):
... return Coordinate(a.x + b.x, a.y + b.y)
上面的@wrapper
等价于add = wrapper(add)
,写法更优雅