Python更喜欢内置函数的未分配本地函数

时间:2011-07-07 21:27:38

标签: python compatibility

以下Python脚本适用于Python 2.3和Python 2.4(没有all()的内置定义:

#! /usr/bin/env python
# vim: set fileencoding=utf-8
# (c) Uwe Kleine-König
# GPLv2

import locale
import sys

f = file(sys.argv[1])
data = f.read()

def len_utf8_char(data):
    if not 'all' in dir(__builtins__):
        def all(seq):
            for i in seq:
                if not i:
                    return False
            return True

    def check_cont(num):
        if all(map(lambda c: ord(c) >= 0x80 and ord(c) <= 0xbf, data[1:num])):
            return num
        else:
            return -1

    if ord(data[0]) < 128:
        # ASCII char
        return 1
    elif ord(data[0]) & 0xe0 == 0xc0:
        return check_cont(2)
    elif ord(data[0]) & 0xf0 == 0xe0:
        return check_cont(3)
    elif ord(data[0]) & 0xf8 == 0xf0:
        return check_cont(4)
    elif ord(data[0]) & 0xfc == 0xf8:
        return check_cont(5)
    elif ord(data[0]) & 0xfe == 0xfc:
        return check_cont(6)

i = 0
maxl = 0
while i < len(data):
    l = len_utf8_char(data[i:])
    if l < 0:
        prefenc = locale.getpreferredencoding()
        if prefenc not in ('UTF-8', 'ANSI_X3.4-1968'):
            print prefenc
        else:
            print 'ISO-8859-1'
        sys.exit(0)

    if maxl < l:
        maxl = l
    i += l

if maxl > 1:
    print 'UTF-8'
else:
    print 'ANSI_X3.4-1968'

现在使用Python 2.5及更高版本会失败如下:

$ python2.5 guess-charmap guess-charmap
Traceback (most recent call last):
  File "guess-charmap", line 43, in <module>
    l = len_utf8_char(data[i:])
  File "guess-charmap", line 30, in len_utf8_char
    return check_cont(2)
  File "guess-charmap", line 21, in check_cont
    if all(map(lambda c: ord(c) >= 0x80 and ord(c) <= 0xbf, data[1:num])):
NameError: free variable 'all' referenced before assignment in enclosing scope

删除所有的兼容性定义修复了Python 2.5+的问题。 我想知道为什么Python在这种情况下不会选择内置all()。有人可以解释一下吗?

4 个答案:

答案 0 :(得分:5)

当Python解析函数体时,它会查找赋值中使用的变量名。除非使用global变量声明,否则所有这些变量都假定为本地变量。

def all为变量名all指定一个值。尽管赋值在if-block内,但all在所有情况下都被视为局部变量(无论if-block是否稍后执行)。

如果未执行if-block,all将成为未绑定的局部变量,从而引发NameError。

如果您将if not 'all' ...块移到def len_utf8_char之外,那么 你会避免这个问题。

答案 1 :(得分:3)

出于同样的原因,它发生在变量上;编译器已将其标记为函数的本地,因此期望它是本地的。如果您想解决这个问题,那么只需在all = __builtins__.all子句中执行else

答案 2 :(得分:2)

您可以将all的定义放在模块级别,如下所示:

try:
    all
except NameError:
    def all(seq):
        for i in seq:
            if not i:
                return False
        return True

答案 3 :(得分:0)

因为当您在all()之后定义函数时,仍然在本地范围内。 为什么函数内部有这么多函数定义? 为什么要定义all()? 为什么不使用这个词典

   if ord(data[0]) < 128:
        # ASCII char
        return 1
    elif ord(data[0]) & 0xe0 == 0xc0:
        return check_cont(2)
    elif ord(data[0]) & 0xf0 == 0xe0:
        return check_cont(3)
    elif ord(data[0]) & 0xf8 == 0xf0:
        return check_cont(4)
    elif ord(data[0]) & 0xfc == 0xf8:
        return check_cont(5)
    elif ord(data[0]) & 0xfe == 0xfc:
        return check_cont(6)

事实上,我会要求重写这段代码,这很复杂而烦人。