Nick分享的一些Python知识

标签:Python

今天在Nick Johnson的博客看到一篇《Python Gotchas》,觉得很不错,就稍微翻译了一些。
  • 递归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相关的知识,也是一个可能经常会犯的错误,因为文档里就有类似的例子。
    entities = Entity.all().filter('foo =', bar)
    for entity in entities:
      entity.number += 1
    db.put(entities)
    由于没调用fetch()方法,entities其实是个Query对象,而不是实体集。
    但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。
    def f():
      x = '1'
      def g():
        x += '2'
        return x
      return g
    print f()()
    如果要更改外部作用域里的变量,最简单的办法就是将其放入全局作用域,用global关键字引入该变量。
    x = ''
    def f():
      global x
      x = '1'
      def g():
        global x
        x += '2'
        return x
      return g
    print f()()
    但这种方法显得很丑陋,让一个本该是f()的局部变量变成全局变量,而且还多出了2个global语句。
    实际上Python只是不让局部作用域里的代码更改全局作用域里的变量本身,但可以更改变量的内容,所以调用该变量的方法来更改它是合法的。
    def f():
      x = ['1']
      def g():
        x.append('2')
        return ''.join(x)
      return g
    print f()()
    这种方法没有污染到全局命名空间,却也实现了相同的效果。
    这在一定程度上解决了之前我所遇到的一个闭包问题,详情可见《Python的闭包与nonlocal》

0条评论 你不来一发么↓

    想说点什么呢?