Nick分享的一些Python知识
2009 11 15 11:10 PM 1967次查看
- 递归import
这个问题也曾经难倒过我,就是a模块里用到了b模块中的变量,而b模块中又用到了a模块的变量,会使得Python出现递归import的错误。
实际上当第一次import一个模块时,Python会创建一个新的全局作用域,并在该作用域里执行这个模块,然后将该作用域赋值给你import的模块名。
由于这是个执行过程所以模块间相互import就相当于没有终止条件的递归调用了,自然会出错。
解决的办法是修改你的模块,让其不存在相互依赖的关系。如果没法做到的话,还有其他的办法。
例如a模块的fa函数要调用b模块的fb函数,而b模块的gb函数要调用a模块的ga函数,那么可以只在fa函数里面import b。由于执行a模块时,fa函数只解析,不执行,所以内部的import b不会造成递归import;而执行fa函数时,因为b模块已经成功载入,所以调用b.fb是合法的。 - 迭代查询对象
这是一个GAE相关的知识,也是一个可能经常会犯的错误,因为文档里就有类似的例子。
由于没调用fetch()方法,entities其实是个Query对象,而不是实体集。entities = Entity.all().filter('foo =', bar) for entity in entities: entity.number += 1 db.put(entities)
但Query对象同样可以迭代,而且每次迭代过程都会进行一次fetch,但这里我们取出来的实体entity修改后并不会更改查询对象entities,所以没有效果。
之后db.put()同样可以接受一个迭代对象,但这个查询对象并没有进行任何更改,所以它又遍历了一遍数据库,取出实体,然后不做任何更改将其保存回数据库。 - 保留模块名
这同样也是GAE相关的知识。GAE上禁用了一些不安全的标准模块,因此这些模块是不能import的。
一般来说这不会造成很大影响,但如果你自己写了个模块,而它的模块名在禁用模块列表中,那么它就变得可import了。
对于你自己的程序而言,这可能没什么影响,但你用到的其他库可能依赖于这些模块,而它们可能会import错误的模块。
所以最好别使用标准模块名作为自己的模块名,例如email.py。 - 全局变量和别名
Python里只有2种作用域:全局作用域和局部作用域。全局作用域是指当前代码所在模块的作用域,局部作用域是指当前函数或方法所在的作用域。其实准确来说,Python 3.x引入了nonlocal关键字,可以用于标识外部作用域的变量。
局部作用域里的代码可以读外部作用域(包括全局作用域)里的变量,但不能更改它。一旦进行更改,就会将其当成是局部变量。而如果在更改前又进行了读取操作,则会抛出异常。
例如下面这段代码就会抛出异常:UnboundLocalError: local variable 'x' referenced before assignment。
如果要更改外部作用域里的变量,最简单的办法就是将其放入全局作用域,用global关键字引入该变量。def f(): x = '1' def g(): x += '2' return x return g print f()()
但这种方法显得很丑陋,让一个本该是f()的局部变量变成全局变量,而且还多出了2个global语句。x = '' def f(): global x x = '1' def g(): global x x += '2' return x return g print f()()
实际上Python只是不让局部作用域里的代码更改全局作用域里的变量本身,但可以更改变量的内容,所以调用该变量的方法来更改它是合法的。
这种方法没有污染到全局命名空间,却也实现了相同的效果。def f(): x = ['1'] def g(): x.append('2') return ''.join(x) return g print f()()
这在一定程度上解决了之前我所遇到的一个闭包问题,详情可见《Python的闭包与nonlocal》。
0条评论 你不来一发么↓