5

我定义了一个接收可选参数的函数,使用小数默认值:

def foo(x=0.1):
    pass

现在foo(在 IDLE shell 中输入时,弹出的帮助我完成调用的工具提示显示为(x=0<tuple>),而不是预期的(x=0.1). 我以前从未遇到过这种情况,尽管我很难相信我没有使用任何带有小数默认值的函数/方法。

假设它是一个功能,而不是一个错误,如果有人能解释它为什么会发生,我会很高兴。我在 Windows 7 上使用 python 2.7.5 64 位。

编辑:

从评论来看,它似乎不是一个功能。根据 2rs2ts 的建议,我检查了不同的函数定义,并发现我试图在工具提示中替换小数点的每一个外观。所以这个定义——

def foo(x=[(1,0.1), 2, .3]):
    pass

生成工具提示(x=[(1, 0<tuple>), 2, 0<tuple>])

我应该关闭这个问题并提交错误报告吗?

4

2 回答 2

3

这是一个奇怪的答案,发现它有点像一场野鹅追逐......

我没有看到bugs.python.org上发布的问题,但经过一番摸索,我在 Python 2.6.6 中找到了 CallTips.py 文件,并且看到了可能有问题的代码行。通过向下滚动到get_arg_text()方法中的第 161 行,我看到

arg_text = "(%s)" % re.sub("\.\d+", "<tuple>", arg_text)

这看起来就像您在问题中发布的内容,并且确实如果arg_text将浮点数转换为字符串,则该行返回<tuple>字符串:

arg_text = "(%s)" % re.sub("\.\d+", "<tuple>", "9.0")    # returns (9<tuple>)

但是,该问题必须已在svn.python.org/.../Calltips.py(在 PEP 384 期间?)得到修复,因为该版本没有上述行。事实上,get_arg_text()已被get_argspec().

所以答案似乎是在 PEP 384 期间修复。根据对您问题的评论,Python 3.3 的 IDLE 有这个修复,但正如您所指出的,Python 2.7.5 没有。为了比较,我粘贴了以下两种方法,以便有人能够准确解释 PEP 384 如何解决您看到的问题。

希望能帮助到你。

仅供参考:

Calltips.py 的旧版本get_arg_text(ob)(至少与您正在使用的 2.7.5 版本一样)。例如,它位于Mac 上的/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/idlelib/CallTips.py 。函数定义如下:

def get_arg_text(ob):
    """Get a string describing the arguments for the given object"""
    arg_text = ""
    if ob is not None:
        arg_offset = 0
        if type(ob) in (types.ClassType, types.TypeType):
            # Look for the highest __init__ in the class chain.
            fob = _find_constructor(ob)
            if fob is None:
                fob = lambda: None
            else:
                arg_offset = 1
        elif type(ob)==types.MethodType:
            # bit of a hack for methods - turn it into a function
            # but we drop the "self" param.
            fob = ob.im_func
            arg_offset = 1
        else:
            fob = ob
        # Try to build one for Python defined functions
        if type(fob) in [types.FunctionType, types.LambdaType]:  # <- differs here!
            argcount = fob.func_code.co_argcount
            real_args = fob.func_code.co_varnames[arg_offset:argcount]
            defaults = fob.func_defaults or []
            defaults = list(map(lambda name: "=%s" % repr(name), defaults))
            defaults = [""] * (len(real_args) - len(defaults)) + defaults
            items = map(lambda arg, dflt: arg + dflt, real_args, defaults)
            if fob.func_code.co_flags & 0x4:
                items.append("...")
            if fob.func_code.co_flags & 0x8:
                items.append("***")
            arg_text = ", ".join(items)
            arg_text = "(%s)" % re.sub("\.\d+", "<tuple>", arg_text)
        # See if we can use the docstring
        doc = getattr(ob, "__doc__", "")
        if doc:
            doc = doc.lstrip()
            pos = doc.find("\n")
            if pos < 0 or pos > 70:
                pos = 70
            if arg_text:
                arg_text += "\n"
            arg_text += doc[:pos]
    return arg_text

位于 svn.python.org/.../Calltips.py 的相应函数似乎已经修复了一个错误。该方法已重命名为get_argspec

def get_argspec(ob):
    """Get a string describing the arguments for the given object."""
    argspec = ""
    if ob is not None:
        if isinstance(ob, type):
            fob = _find_constructor(ob)
            if fob is None:
                fob = lambda: None
        elif isinstance(ob, types.MethodType):
            fob = ob.__func__
        else:
            fob = ob
        if isinstance(fob, (types.FunctionType, types.LambdaType)):
            argspec = inspect.formatargspec(*inspect.getfullargspec(fob))
            pat = re.compile('self\,?\s*')
            argspec = pat.sub("", argspec)
        doc = getattr(ob, "__doc__", "")
        if doc:
            doc = doc.lstrip()
            pos = doc.find("\n")
            if pos < 0 or pos > 70:
                pos = 70
            if argspec:
                argspec += "\n"
            argspec += doc[:pos]
    return argspec
于 2013-07-06T02:08:48.227 回答
2

感谢 Gary 和 Ariel 的侦探工作,我能够通过"(?<!\d)"在替换 re 的开头添加否定的lookbehind 断言来解决这个问题。例如,re 现在匹配“.0”,第一个参数元组的有趣“名称”,它从不跟随数字,但不匹配“0.0”,浮点的字符串表示,总是以数字开头. CPython 跟踪器问题 18539

于 2013-07-26T22:37:26.910 回答