Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1792660
  • 博文数量: 335
  • 博客积分: 4690
  • 博客等级: 上校
  • 技术积分: 4341
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-08 21:38
个人简介

无聊之人--除了技术,还是技术,你懂得

文章分类

全部博文(335)

文章存档

2016年(29)

2015年(18)

2014年(7)

2013年(86)

2012年(90)

2011年(105)

分类: Python/Ruby

2011-08-27 15:34:11

8.5. locals and globals

Let's digress from HTML processing for a minute and talk about how Python handles variables. Python has two built-in functions, locals and globals, which provide dictionary-based access to local and global variables.

我们从html处理过程岔开一段时间,来讨论一下如何python如何处理变量。Python有两个内置函数,locals&globals,它提供一种基于字典的方法来访问局部变量和全局变量。

Remember locals? You first saw it here:

还记得局部变量么?让我们首先看看它:

 

  1. def unknown_starttag(self, tag, attrs):
  2.         strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs])
  3.         self.pieces.append("<%(tag)s%(strattrs)s>" % locals())

No, wait, you can't learn about locals yet. First, you need to learn about namespaces. This is dry stuff, but it's important, so pay attention.

对了,等一等,你还没有学过局部变量。首先,你需要学习命名空间。这是十分枯燥的事情,但是它是如此的重要,因此你需要认真对待。

Python uses what are called namespaces to keep track of variables. A namespace is just like a dictionary where the keys are names of variables and the dictionary values are the values of those variables. In fact, you can access a namespace as a Python dictionary, as you'll see in a minute.

Python使用所谓的命名空间来跟踪变量。一个命名空间就如同一个字典,其中键是变量的名字,字典值是这些变量的值。事实上,正如你稍后马上就要看到的那样,你可以通过字典的方式来访问一个命名空间。

At any particular point in a Python program, there are several namespaces available. Each function has its own namespace, called the local namespace, which keeps track of the function's variables, including function arguments and locally defined variables. Each module has its own namespace, called the global namespace, which keeps track of the module's variables, including functions, classes, any other imported modules, and module-level variables and constants. And there is the built-in namespace, accessible from any module, which holds built-in functions and exceptions.

Python程序中的任意时候,都包含几个命名空间变量。每一个函数都有一个自己的命名空间,被称之为局部命名空间,它能跟踪函数变量,包括函数参数以及局部定义的变量。每一个模块都有自己的命名空间,称之为全局命名空间,它可以跟踪模块变量,主要包括函数,类,以及任何其它导入模块,模块级别的变量以及常量。存在一个内置的命名空间,从任何模块中都可以访问,它包含了内置函数以及异常。

When a line of code asks for the value of a variable x, Python will search for that variable in all the available namespaces, in order:

当一行代码对一个变量进行求值时,Python按顺序在所有的命名空间中进行搜索:

1.        local namespace - specific to the current function or class method. If the function defines a local variable x, or has an argument x, Python will use this and stop searching.

2.        本地命名空间---特定于当前的函数,或是类,或是类方法。如果函数定义了一个剧局部变量,或是一个形式参数,Python将使用该变量然后停止搜索

3.        global namespace - specific to the current module. If the module has defined a variable, function, or class called x, Python will use that and stop searching.

4.        全局命名空间特定于当前的模块。如果该模块定义一个变量,函数或是类,称之为XPython将会使用改值,然后停止搜索

5.        built-in namespace - global to all modules. As a last resort, Python will assume that x is the name of built-in function or variable.

6.        内置的命名空间---对全部模块都使用。作为最后求助的对象,Python假定X是一个内置函数或是变量的名字。

If Python doesn't find x in any of these namespaces, it gives up and raises a NameError with the message There is no variable named 'x', which you saw back in Example 3.18, “Referencing an Unbound Variable”, but you didn't appreciate how much work Python was doing before giving you that error.

如果Python没有在上述的命名空间中找到x,它将停止搜索,然后抛出一个NameError的异常,并提示:没有名字的x的变量,你可以退回到在例3.8--引用未绑定变量那部分看一下,但是在Python抛出该错误以前,不要对Python所作的工作表示感激。

Important

 

Python 2.2 introduced a subtle but important change that affects the namespace search order: nested scopes. In versions of Python prior to 2.2, when you reference a variable within a nested function or lambda function, Python will search for that variable in the current (nested or lambda) function's namespace, then in the module's namespace. Python 2.2 will search for the variable in the current (nested or lambda) function's namespace, then in the parent function's namespace, then in the module's namespace. Python 2.1 can work either way; by default, it works like Python 2.0, but you can add the following line of code at the top of your module to make your module work like Python 2.2:

Python2.2 引进了一个微小但是十分重要的改变:它修改了命名空间的修改顺序:嵌套区域。在Python 2.2以前的版本,当你在嵌套函数或是lamda函数内引用一个变量,Python将会对变量按一下顺序搜索变量:当前(嵌套的或是lamda)函数的命名空间,接着是模块命名空间。Python 2.2 将会首先在当前函数(嵌套函数,lamda函数)的命名空间内寻找,然后是父函数的命名空间,接着是模块的命名空间。Python2.1 两种方式都可以:默认是它的行为同Python2.0类似,但是你可以你模块的顶部添加下面的代码,它就会按照Python2.2的方式搜索。

from __future__ import nested_scopes

 

Are you confused yet? Don't despair! This is really cool, I promise. Like many things in Python, namespaces are directly accessible at run-time. How? Well, the local namespace is accessible via the built-in locals function, and the global (module level) namespace is accessible via the built-in globals function.

你是不是迷惑了?不要灰心!这才是真正有趣的地方,我保证,正如Python所有内容一样,命名空间可以在运行时直接访问。如何访问呢?

Example 8.10. Introducing locals

8.8 locals 简介

  1. >>> def foo(arg):
  2. ... x = 1
  3. ... print locals()
  4. ...
  5. >>> foo(7)
  6. {'arg': 7, 'x': 1}
  7. >>> foo('bar')
  8. {'arg': 'bar', 'x': 1}

1

The function foo has two variables in its local namespace: arg, whose value is passed in to the function, and x, which is defined within the function.

函数foo在本地命名空间中包含两个变量:arg,它的值是通过函数传递进去的,而x在函数的内部定义。

2

locals returns a dictionary of name/value pairs. The keys of this dictionary are the names of the variables as strings; the values of the dictionary are the actual values of the variables. So calling foo with 7 prints the dictionary containing the function's two local variables: arg (7) and x (1).

Locals返回一个名值对的字典。字典的键为变量名字的字符串形式;字典的值为变量的实际值。因此使用7来调用foof将打印出字典所包含函数的两个局部变量:arg(7)&x1)。

3

Remember, Python has dynamic typing, so you could just as easily pass a string in for arg; the function (and the call to locals) would still work just as well. localsworks with all variables of all datatypes.

记住,Python包含动态类型,因此你可以简单的为arg传一个字符串;函数(对local的调用)仍然如同往常一样工作。Locals使用于所有类型的所有变量。

What locals does for the local (function) namespace, globals does for the global (module) namespace. globals is more exciting, though, because a module's namespace is more exciting.[3] Not only does the module's namespace include module-level variables and constants, it includes all the functions and classes defined in the module. Plus, it includes anything that was imported into the module.

Locals适用于本地命名空间,而global是使用于全局命名空间。然而全局命名空间更有意思,这是因为模块的命名空间更加有趣,不仅是因为模块的命名空间包含了模块级的变量和常量,它还包括定义在模块中的所有的类和函数。除此职位,它还包含了模块中所导入的所有对象。

Remember the difference between from module import and import module? With import module, the module itself is imported, but it retains its own namespace, which is why you need to use the module name to access any of its functions or attributes: module.function. But with from module import, you're actually importing specific functions and attributes from another module into your own namespace, which is why you access them directly without referencing the original module they came from. With the globals function, you can actually see this happen.

你还记得from module import &import module 这二者之间的区别?通过import module,模块本身被导入,但是它还包含在自己的命名空间中,这就是你为什么需要使用模块名字来访问它的函数或是属性的原因:moduleFunction。但是使用from module import,你实际上是从另一个模块向你的命名空间导入一个确定的函数以及属性,这也是你可以直接访问它们,而不需要引用最初的模块名字来确定它们来自何处的原因。。使用globals函数,你看到它们确实如此。

Example 8.11. Introducing globals

Look at the following block of code at the bottom of BaseHTMLProcessor.py:

 

  1. if __name__ == "__main__":
  2.     for k, v in globals().items():
  3.         print k, "=", v

1

Just so you don't get intimidated, remember that you've seen all this before. The globals function returns a dictionary, and you're iterating through the dictionary using the items method and multi-variable assignment. The only thing new here is the globals function. 

因此你不必害怕,记住这些你早已经看过。Globals函数返回一个字典,你使用items方法以及多个变量同时赋值来迭代该字典。这儿对你来说唯一的新知识点就是globals函数。

Now running the script from the command line gives this output (note that your output may be slightly different, depending on your platform and where you installedPython):

现在你在命令行运行该脚本,输出(注意输入可能略有不同,这依赖你的平台以及Python的安装位置)如下:

  1. c:\docbook\dip\py> python BaseHTMLProcessor.py
  2. SGMLParser = sgmllib.SGMLParser
  3. htmlentitydefs = <module 'htmlentitydefs' from 'C:\Python23\lib\htmlentitydefs.py'>
  4. BaseHTMLProcessor = __main__.BaseHTMLProcessor
  5. __name__ = __main__
  6. ... rest of output omitted for brevity..

.

出于间接性,剩余的输入省略。

1

SGMLParser was imported from sgmllib, using from module import. That means that it was imported directly into the module's namespace, and here it is.

SGMLParsersgmllib模块中导入,使用from module import。这意味它是直接被导入模块的命名空间,事实上确实如此。

 

 

2

Contrast this with htmlentitydefs, which was imported using import. That means that the htmlentitydefs module itself is in the namespace, but the entitydefs variable defined within htmlentitydefs is not.

htmlentitydefs相反,它是使用imported导入。这意味着htmlentitydefs模块本身仍然还在自己的命名空间中,但是定义在htmlentitydefs中的变量不在其中。

 

 

3

This module only defines one class, BaseHTMLProcessor, and here it is. Note that the value here is the class itself, not a specific instance of the class.

该模块仅定义了一个类:BaseHTMLProcessor,它就在此处。注意:改变量值是类本身,不是某个特定的类实例。

 

 

4

Remember the if __name__ trick? When running a module (as opposed to importing it from another module), the built-in __name__ attribute is a special value, __main__. Since you ran this module as a script from the command line, __name__ is __main__, which is why the little test code to print the globals got executed.

 

 

 

Note

 

 

Using the locals and globals functions, you can get the value of arbitrary variables dynamically, providing the variable name as a string. This mirrors the functionality of the getattr function, which allows you to access arbitrary functions dynamically by providing the function name as a string.

使用locals&globals函数,你可以动态的获取任意一个变量的值,通过使用字符串形式的变量名。这反映出getattr函数的功能,它允许你通过使用字符串形式的函数名来动态的访问函数。

 

 

There is one other important difference between the locals and globals functions, which you should learn now before it bites you. It will bite you anyway, but at least then you'll remember learning it.

localsglobals之间还有另外十分重要的区别:在它以任意方式反噬你前,你需要掌握它,但是至少你记得你将马上学习它。

Example 8.12. locals is read-only, globals is not

8.12Locals是只读的,globals可读写

    1. def foo(arg):
    2. x = 1
    3. print locals()
    4. locals()["x"] = 2
    5. print "x=",x
    6. z = 7
    7. print "z=",z
    8. foo(3)
    9. globals()["z"] = 8
    10. print "z=",z

1

Since foo is called with 3, this will print {'arg': 3, 'x': 1}. This should not be a surprise.

因为使用 3来调用foo,它将打印{'arg': 3, 'x': 1}.这没有什么值得惊讶的。

2

locals is a function that returns a dictionary, and here you are setting a value in that dictionary. You might think that this would change the value of the local variable xto 2, but it doesn't. locals does not actually return the local namespace, it returns a copy. So changing it does nothing to the value of the variables in the local namespace.

Locals是一个返回字典的函数,并且这儿你正在对字典中某个值进行重新设值。你或许会认为这回改变局部变量的值,即x =2,但是事实上根本不是。Locals实际上并没有返回本地的命名空间,它返回是一个copy。因此对本地命名空间的修改将不改变过本地命名空间中的任何对象。

3

This prints x= 1, not x= 2.

打印x =1,而不是x =2.

4

After being burned by locals, you might think that this wouldn't change the value of z, but it does. Due to internal differences in how Python is implemented (which I'd rather not go into, since I don't fully understand them myself), globals returns the actual global namespace, not a copy: the exact opposite behavior of locals. So any changes to the dictionary returned by globals directly affect your global variables.

在被locals函数激怒以后,你或许会认为这同样也不会改变z的值,但是它的确改变了。由于Python不同实现的原因(我不打算深入研究,因为我自己也没有完全明白),globals返回实际的全局命名空间,而不是一份copy:这同本地命名空间的行为刚好相反。因此对全局变量的任何改变都将影响你的全局变量。

5

This prints z= 8, not z= 7.

打印z = 8 而不是z=7.

digress英音:[dai'gres, 离题,把(话题)离开

                                              

阅读(1751) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~