本节目标:
当我们使用turtle库中的类时,我们用turtle.Turtle
。为什么要把库名加上? 原因很容易想到,因为别的库中也可能有Turtle
。
y = 3
def func():
y = 1
print("函数func:", y) # 输出:1
func()
print("函数外:", y) # 输出:3
运行以上代码我们发现,在函数里面对y
的值进行改变似乎没有影响到函数外y
的值。
Learning By Reading 难度:★★ 重要性:★★★★★
材料中有一个链接很好地解释了“闭包”的概念。
里面提到的“装饰器”将在下一节介绍,可以先跳过与“装饰器”有关的部分。
另一个例子,
def polygon_factory(n):
# 返回一个正n边形函数polygon
def polygon(turtle, side):
return turtle.polygon(n, side) # 绑定了闭包polygon_factory中的名称n和局部名称空间中的turtle和side
# 翻译成人话即这里的n用的是polygon_factory的参数n,而turtle和side是局部变量
return polygon
pentagon = polygon_factory(5) # 五边形函数
octagon = polygon_factory(8) # 八边形函数
my_turtle = MyTurtle()
pentagon(my_turtle, 50) # 边长为50的五边形
octagon(my_turtle, 50) # 边长为50的八边形
每个名称都有自己的“作用域”(scope),即这个名称可以在哪个范围内被绑定。 比如上面的turtle
和side
,其作用域是polygon
这个函数。 出了这个函数,Python就不认turtle
和side
这个名字了。 而polygon
和n
,其作用域是polygon_factory
这个函数,也包括在polygon_factory
里面定义的polygon
函数。
def polygon_factory(n):
def polygon(turtle, side):
print(n, polygon) # 可以
print(turtle, side) # 可以
return turtle.polygon(n, side)
print(n, polygon) # 可以
print(turtle) # 报错
print(side) # 报错
return polygon
而靠里面的名称会覆盖掉靠外面的名称,本节第一段代码就是例子。
另外一点需要注意的是,函数体中的名称,其作用域可以扩展到函数中定义的函数里。 就像上面的n
可以在polygon
中使用。
但类体中的名称不会扩展到类方法和列表解析中。
master = "Your Name"
class MyTurtle(turtle.Turtle):
yet_another_master = "Your BF/GF's Name"
other_masters = [yet_another_master + str(i) for i in range(42)] # 不可以
print(master) # 可以,输出全局变量master
print(yet_another_master) # 可以
def polygon(self):
print(master) # 可以
print(yet_another_master) # 报错
class MyOtherTurtle(object):
master = "Your Nickname"
other_masters = [master + str(i) for i in range(42)] # 可以,但这里的master是全局变量master,即"Your Name",而不是"Your Nickname"
def polygon(self):
print(master) # 可以,仍然是"Your Name",而不是"Your Nickname"
即x
的作用域延伸到了some_method
里,但y
的作用域不能。
另一个区别是
master = "Your Name"
def my_turtle():
yet_another_master = master # 报错:UnboundLocalError,Python认为x这时候还没有赋值
master = 42
class MyTurtle(turtle.Turtle):
yet_another_master = master # 可以,虽然这个时候局部名称master还没有绑定,但因为是在类体中,所以Python会用全局变量master
master = "Your Nickname"
print(MyTurtle.master) # 输出:"Your Nickname"
print(MyTurtle.yet_another_master) # 输出:"Your Name"
print(master) # 输出:"Your Name"
在函数中,只要用到了变量x
,那么,函数体中的所有x
都会被绑定到局部名称空间的x
, 所以y = x
的时候会报错说“变量x
在赋值前引用”。
而类体中,遇到这种情况时,Python会自己去全局名称空间里面找x
。
master = "Your Name"
def get_my_turtle():
master = "Your Nickname"
class MyTurtle(turtle.Turtle):
yet_another_master = master # 由于局部名称空间中存在master,所以会有UnboundLocalError,但这是类体,所以Python会去全局名称空间找x,找到全局空间中的master是"Your Name"
master = "Your GF/BF's Name"
return MyTurtle
MyTurtle = get_my_turtle()
print(MyTurtle.master, MyTurtle.yet_another_master) # 输出:"Your GF/BF's Name","Your Name"
# 注意两个MyTurtle的区别。既然我们已经讲了好多好多名称空间呀作用域呀之类的例子了,不许再分不清了~!(..•˘_˘•..)