gpt4 book ai didi

Python 动态帮助和自动完成生成

转载 作者:行者123 更新时间:2023-11-28 21:26:01 25 4
gpt4 key购买 nike

我几乎得到了我想要的......

这个动态对象封装了一个动态文档字符串生成的通用函数调用:

def add_docs(tool):  
def desc(func):
func.__doc__ = "Showing help for %s()" % tool
return func
return desc

class Dynamic(object):
def __getattr__(self, value):
@add_docs(value)
def mutable_f(*args, **kwargs):
print "Calling:", value
print "With arguments:", args, kwargs

return mutable_f

它按预期工作:

>>> Dynamic().test(1, input='file')
Calling: test
With arguments: (1,) {'input': 'file'}
>>> Dynamic().test.__doc__
'Showing help for test()'

唯一的两个问题是帮助显示mutable_f 签名

>>> help(Dynamic().test)
Help on function mutable_f in module __main__:

mutable_f(*args, **kwargs)
Showing help for test()
(END)

并且没有自动完成(我可以即时获取有效函数列表,并缓存它,因为该操作很昂贵)

我认为第一个是无法解决的,但我对第二个不太确定。想法?

最佳答案

自动完成最常使用 dir() function 的输出, 可以 Hook 。只需实现一个 __dir__() 方法:

def __dir__(self):
res = dir(type(self)) + list(self.__dict__.keys())
res.extend(['dynamic1', 'dynamic2'])
return res

至于在匹配函数签名的同时包装函数,您需要基于该签名构建外观。我有 done exactly that for a Zope security feature :

import inspect
import functools


class _Default(object):
def __init__(self, repr):
self._repr = repr
def __repr__(self):
return self._repr


def _buildFacade(name, spec, docstring):
"""Build a facade function, matching the decorated method in signature.

Note that defaults are replaced by instances of _Default, and _curried
will reconstruct these to preserve mutable defaults.

"""
args = inspect.formatargspec(
formatvalue=lambda v: '=_Default({0!r})'.format(repr(v)), *spec)
callargs = inspect.formatargspec(formatvalue=lambda v: '', *spec)
return 'def {0}{1}:\n """{2}"""\n return _curried{3}'.format(
name, args, docstring, callargs)


def add_docs(tool):
spec = inspect.getargspec(tool)
args, defaults = spec[0], spec[3]

arglen = len(args)
if defaults is not None:
defaults = zip(args[arglen - len(defaults):], defaults)
arglen -= len(defaults)

def _curried(*args, **kw):
# Reconstruct keyword arguments
if defaults is not None:
args, kwparams = args[:arglen], args[arglen:]
for positional, (key, default) in zip(kwparams, defaults):
if isinstance(positional, _Default):
kw[key] = default
else:
kw[key] = positional

return tool(*args, **kw)

name = tool.__name__
doc = 'Showing help for {0}()'.format(name)
facade_globs = dict(_curried=_curried, _Default=_Default)
exec _buildFacade(name, spec, doc) in facade_globs

wrapped = facade_globs[name]
wrapped = functools.update_wrapper(wrapped, tool,
assigned=filter(lambda w: w != '__doc__', functools.WRAPPER_ASSIGNMENTS))

return facade_globs[name]

当涉及到方法签名时,这将做正确的事情,几乎。您无法在此处绕过可变默认值,需要显式处理这些默认值以保留它们。

一个小演示:

>>> def foo(bar, spam='eggs', foobarred={}):
... foobarred[bar] = spam
... print foobarred
...
>>> documented = add_docs(foo)
>>> help(documented)
Help on function foo:

foo(bar, spam='eggs', foobarred={})
Showing help for foo()

>>> documented('monty', 'python')
{'monty': 'python'}
>>> documented('Eric', 'Idle')
{'Eric': 'Idle', 'monty': 'python'}

整个 _Default 舞蹈需要保留可变默认值,虽然这通常是一个坏主意,但确实需要继续按原计划工作。构建的外观将看起来和原来的一样,并且会像它一样工作,但可变对象继续存在于“正确”的位置。

请注意,外观已更新以尽可能接近原始外观;通过使用 functools.update_wrapper各种元数据从原始文件复制到外观,但我们注意从中排除 __doc__ 字符串,因为我们的外观明确使用它自己的文档字符串。

关于Python 动态帮助和自动完成生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13603088/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com