CoderXL's Blog

Back

随笔 →

哪段代码会报错?

greetings = "Hi, nice to meet you."

class Class:
    def func(self):
        def nested_func():
            print(greetings)
        
        nested_func()

obj = Class()
obj.func()
python

答案是 Case #2,它会报错:

NameError: name 'greetings' is not defined
text

其余五段代码都能正常输出 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 访问这个属性,就可以正常输出了。

所以,函数可以直接找到外层函数里的名字,但类里的属性,需要通过对象或类来访问。

Comment seems to stuck. Try to refresh?✨