哪段代码会报错?
greetings = "Hi, nice to meet you."
class Class:
def func(self):
def nested_func():
print(greetings)
nested_func()
obj = Class()
obj.func()pythonclass Class:
greetings = "Hi, nice to meet you."
def func(self):
def nested_func():
print(greetings)
nested_func()
obj = Class()
obj.func()pythonclass Class:
def func(self):
greetings = "Hi, nice to meet you."
def nested_func():
print(greetings)
nested_func()
obj = Class()
obj.func()pythonclass Class:
def func(self):
def nested_func():
greetings = "Hi, nice to meet you."
print(greetings)
nested_func()
obj = Class()
obj.func()pythonclass Class:
def func(self):
def nested_func():
print(greetings)
greetings = "Hi, nice to meet you."
nested_func()
obj = Class()
obj.func()pythonclass Class:
def func(self):
def nested_func():
print(greetings)
nested_func()
greetings = "Hi, nice to meet you."
obj = Class()
obj.func()python答案是 Case #2,它会报错:
NameError: name 'greetings' is not definedtext其余五段代码都能正常输出 Hi, nice to meet you.。
奇怪,greetings 明明就在类里面,怎么还找不到呢?
这涉及到 Python 查找名字的机制。
找 · 名 · 字#
在函数里直接使用一个名字时,Python 会按照 LEGB 的顺序查找,找到就停下来:
- L(Local):当前函数里面。
- E(Enclosing):包在外面的函数里面。如果套了好几层函数,就从内向外找。
- G(Global):当前模块的全局作用域,也就是这些例子里最外层的位置。
- B(Built-in):Python 内置的名字,比如
print、len.
一路找完还没有,就会报 NameError.
对照前面的例子来看:
- Case #4:
greetings就在nested_func()里面,即 L. - Case #3 #5:
greetings在外层的func()里面,即 E. - Case #1 #6:两层函数里面都没有
greetings,继续往外,在 G 找到了。
Case #5 和 Case #6 还有一点容易让人犹豫:greetings 都写在函数定义的后面,这样也可以吗?
可以。执行 def nested_func(): 时,只是定义了函数,还没有执行里面的 print(greetings).
Case #5 在调用 nested_func() 之前,已经给外层函数里的 greetings 赋了值;Case #6 在调用 obj.func() 之前,也已经给全局的 greetings 赋了值。所以等到真正执行 print(greetings) 时,都能找到它。
类 · 里 · 的 · 名 · 字#
再看 Case #2:greetings 写在 class Class: 里面,却不在任何一个函数里面。
函数查找名字时,外层的类不算 LEGB 里的 E.所以这里虽然看起来又套了一层,但 Python 不会去类里面找 greetings.
nested_func() 里面没有,外层的 func() 里面没有,全局和内置的名字里也都没有,最后就报错了。
实际上,类里的 greetings 是一个类属性。如果想访问它,需要把 print(greetings) 改成 print(self.greetings):
class Class:
greetings = "Hi, nice to meet you."
def func(self):
def nested_func():
print(self.greetings)
nested_func()
obj = Class()
obj.func()python这次 nested_func() 先从外层的 func() 找到参数 self,再通过 self.greetings 访问这个属性,就可以正常输出了。
所以,函数可以直接找到外层函数里的名字,但类里的属性,需要通过对象或类来访问。