您当前位置:首页 > 深入 Python > HTML 处理 > 局部变量和全局变量 | << >> | ||||
深入 Python从 Python 新手到专家 |
让我们暂时放下 HTML 处理,谈谈 Python 如何处理变量。 Python 有两个内置函数,locals 和 globals,它们提供基于字典的访问局部变量和全局变量的方式。
还记得 locals 吗?你第一次见到它是在这里
def unknown_starttag(self, tag, attrs): strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs]) self.pieces.append("<%(tag)s%(strattrs)s>" % locals())
不,等等,你还不能学习 locals。首先,你需要了解命名空间。这部分内容可能比较枯燥,但很重要,所以请集中注意力。
Python 使用称为命名空间的东西来跟踪变量。命名空间就像一个字典,其中键是变量的名称,字典值是这些变量的值。事实上,你可以像访问 Python 字典一样访问命名空间,你马上就会看到。
在 Python 程序中的任何特定点,都有几个可用的命名空间。每个函数都有自己的命名空间,称为局部命名空间,它跟踪函数的变量,包括函数参数和局部定义的变量。每个模块都有自己的命名空间,称为全局命名空间,它跟踪模块的变量,包括函数、类、任何其他导入的模块,以及模块级变量和常量。还有一个内置命名空间,可以从任何模块访问,它包含内置函数和异常。
当一行代码请求变量 x 的值时,Python 将按顺序在所有可用的命名空间中搜索该变量
如果 Python 在任何这些命名空间中都找不到 x,它就会放弃并引发一个 NameError,并显示消息 没有名为 'x' 的变量,你在 示例 3.18,“引用未绑定变量” 中已经看到过,但你当时可能没有意识到 Python 在给你这个错误之前做了多少工作。
![]() |
|
Python 2.2 引入了一个微妙但重要的变化,它影响了命名空间搜索顺序:嵌套作用域。在 2.2 之前的 Python 版本中,当你引用 嵌套函数 或 lambda 函数 中的变量时,Python 将在当前(嵌套或 lambda)函数的命名空间中搜索该变量,然后在模块的命名空间中搜索。 Python 2.2 将在当前(嵌套或 lambda)函数的命名空间中搜索该变量,然后在父函数的命名空间中搜索,然后在模块的命名空间中搜索。 Python 2.1 可以采用这两种方式中的任何一种;默认情况下,它的工作方式与 Python 2.0 相同,但你可以在模块的顶部添加以下代码行,使你的模块像 Python 2.2 一样工作from __future__ import nested_scopes |
你是否感到困惑?不要绝望!我保证这真的很酷。就像 Python 中的许多东西一样,命名空间在 运行时可以直接访问。怎么做?嗯,可以通过内置的 locals 函数访问局部命名空间,并可以通过内置的 globals 函数访问全局(模块级)命名空间。
>>> def foo(arg):... x = 1 ... print locals() ... >>> foo(7)
{'arg': 7, 'x': 1} >>> foo('bar')
{'arg': 'bar', 'x': 1}
locals 对局部(函数)命名空间的作用,globals 对全局(模块)命名空间的作用相同。 不过,globals 更令人兴奋,因为模块的命名空间更令人兴奋。[3] 模块的命名空间不仅包括模块级变量和常量,还包括模块中定义的所有函数和类。 此外,它还包括导入到模块中的任何内容。
还记得 from module import 和 import module 之间的区别吗? 使用 import module,模块本身被导入,但它保留了自己的命名空间,这就是为什么你需要使用模块名称来访问它的任何函数或属性:module.function。 但是使用 from module import,你实际上是将特定函数和属性从另一个模块导入到你自己的命名空间中,这就是为什么你可以直接访问它们而无需引用它们来自的原始模块。 使用 globals 函数,你可以实际看到这种情况的发生。
查看 BaseHTMLProcessor.py 底部的以下代码块
if __name__ == "__main__": for k, v in globals().items():print k, "=", v
现在从命令行运行脚本会给出以下输出(请注意,你的输出可能略有不同,取决于你的平台和 Python 的安装位置)
c:\docbook\dip\py> python BaseHTMLProcessor.py
SGMLParser = sgmllib.SGMLParserhtmlentitydefs = <module 'htmlentitydefs' from 'C:\Python23\lib\htmlentitydefs.py'>
BaseHTMLProcessor = __main__.BaseHTMLProcessor
__name__ = __main__
... rest of output omitted for brevity...
![]() |
SGMLParser 是使用 from module import 从 sgmllib 导入的。 这意味着它是直接导入到模块的命名空间中的,它就在这里。 |
![]() |
将此与使用 import 导入的 htmlentitydefs 进行对比。 这意味着 htmlentitydefs 模块本身在命名空间中,但在 htmlentitydefs 中定义的 entitydefs 变量不在命名空间中。 |
![]() |
此模块只定义了一个类,BaseHTMLProcessor,它就在这里。 请注意,这里的值是 类本身,而不是类的特定实例。 |
![]() |
还记得 if __name__ 技巧 吗? 当运行模块(而不是从另一个模块导入它)时,内置的 __name__ 属性是一个特殊值,__main__。 由于你从命令行将此模块作为脚本运行,因此 __name__ 为 __main__,这就是为什么执行用于打印 globals 的小测试代码的原因。 |
![]() |
|
使用 locals 和 globals 函数,你可以动态获取任意变量的值,方法是将变量名称作为字符串提供。 这反映了 getattr 函数的功能,该函数允许你通过将函数名称作为字符串提供来动态访问任意函数。 |
locals 和 globals 函数之间还有一个重要区别,你应该现在就学习它,以免以后被它困扰。 它迟早会困扰你,但至少到那时你还会记得学过它。
def foo(arg): x = 1 print locals()locals()["x"] = 2
print "x=",x
z = 7 print "z=",z foo(3) globals()["z"] = 8
print "z=",z
![]()
[3] 我不太出门。
<< BaseHTMLProcessor.py 简介 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
基于字典的字符串格式化 >> |