12

如果函数的参数预期是某个(或等价的)结构,使用 python 的list, tupleand构建dict,应该如何以及在哪里记录它?

示例文档

def foo(bar):
    """
    Args:
        bar: 2-tuple, ([(<mapping>,<number>), ...], <string>)
    """
    pass

有点麻烦;一些问题:

  • 结构难以阅读
  • 难以表示结构中每个元素的语义含义
  • 如何指示不固定长度
  • 应该只记录一次,还是到处记录
  • 编辑:如何清楚地表明鸭子类型对于元素是可以的(即“dict”与“mapping-like”)

编辑:该示例不是为了尝试强制类型,而是尝试记录结构。就这一点来说,duck typing可以

4

6 回答 6

4

我在工作中遇到了这个问题。根据我的个人研究(即相当彻底的谷歌搜索),没有记录复杂的嵌套函数参数的标准。我最终发明了我的方法,它用于<>表示数据结构的元素,并且每个元素在文档中都有自己的标题和段落。例如:

<options>
---------

A mapping:

  {'years':<years>,
   'states':<states>}

This is the root level of the `options` argument.

<years>
-------

A sequence of integers, each of which is a year to be included in the analysis.


<states>
--------

A sequence of strings, each of which is a state to be included in the analysis.

该文档可以包含在该函数的文档字符串中,但就我而言,我选择将其分解为单独的文档。该方法可以扩展到更复杂的结构。例如,请参阅我的文档here

于 2013-02-12T19:36:52.737 回答
1

如果您使用的是 Python 3,您可能对“函数注释”感兴趣。它们不是强制执行的,完全是可选的,但似乎可以做你想做的事。注释可以是任何 Python 表达式,它们包含在函数头中,在参数旁边。例如(对不起,这有点荒谬):

def fn(name: str, age: int, hobbies: "something else goes here") -> max(2, 9):
  # la la la
  return 9

这里有更多详细信息(包括可能的用例和示例):PEP 3107

于 2013-02-12T06:44:05.193 回答
1

我对您的问题的简单回答是引用Python 的禅宗“显式胜于隐式”。就您的问题而言,这意味着要完整地写出所需的内容,即使需要整个段落来记录单个论点。只需阅读 python 文档即可查看示例。在您的特定情况下,您可以通过引用序列而不是元组来指示鸭子类型(请参阅http://docs.python.org/2/library/collections.html#collections-abstract-base-classes)。

于 2013-02-12T06:10:35.573 回答
0

我见过的最完整的文档字符串规范是NumPy Docstring Style Guide,但我同意它没有提供详细信息来涵盖您的问题。因此,我可能会建议目前可能不存在回答您(和我自己)问题的标准。

于 2013-02-07T18:12:27.230 回答
0

您可以使用装饰器来强制类型以及记录它的方式:

def require(arg_name, *allowed_types):
    '''
    example:
    @require("x", int, float)
    @require("y", float)
    def foo(x, y):
        return x+y
    '''
    def make_wrapper(f):
        if hasattr(f, "wrapped_args"):
            wrapped_args = getattr(f, "wrapped_args")
        else:
            code = f.func_code
            wrapped_args = list(code.co_varnames[:code.co_argcount])

        try:
            arg_index = wrapped_args.index(arg_name)
        except ValueError:
            raise NameError, arg_name
        def wrapper(*args, **kwargs):
            if len(args) > arg_index:
                arg = args[arg_index]
                if not isinstance(arg, allowed_types):
                    type_list = " or ".join(str(allowed_type) for allowed_type in allowed_types)
                    raise Exception, "Expected '%s' to be %s; was %s." % (arg_name, type_list, type(arg))
            else:
                if arg_name in kwargs:
                    arg = kwargs[arg_name]
                    if not isinstance(arg, allowed_types):
                        type_list = " or ".join(str(allowed_type) for allowed_type in allowed_types)
                        raise Exception, "Expected '%s' to be %s; was %s." % (arg_name, type_list, type(arg))

            return f(*args, **kwargs)

        wrapper.wrapped_args = wrapped_args
        return wrapper

    return make_wrapper        
于 2013-02-07T18:00:09.343 回答
0

我认为我最不喜欢的功能,曾经,有非常好的内联文档。

在此处查看validate文档:

Pylons 装饰器 - 验证 - GitHub

def validate(schema=None, validators=None, form=None, variable_decode=False,
         dict_char='.', list_char='-', post_only=True, state=None,
         on_get=False, **htmlfill_kwargs):
"""Validate input either for a FormEncode schema, or individual
validators

Given a form schema or dict of validators, validate will attempt to
validate the schema or validator list.

If validation was successful, the valid result dict will be saved
as ``self.form_result``. Otherwise, the action will be re-run as if
it was a GET, and the output will be filled by FormEncode's
htmlfill to fill in the form field errors.

``schema``
    Refers to a FormEncode Schema object to use during validation.
``form``
    Method used to display the form, which will be used to get the
    HTML representation of the form for error filling.
``variable_decode``
    Boolean to indicate whether FormEncode's variable decode
    function should be run on the form input before validation.
``dict_char``
    Passed through to FormEncode. Toggles the form field naming
    scheme used to determine what is used to represent a dict. This
    option is only applicable when used with variable_decode=True.
``list_char``
    Passed through to FormEncode. Toggles the form field naming
    scheme used to determine what is used to represent a list. This
    option is only applicable when used with variable_decode=True.
``post_only``
    Boolean that indicates whether or not GET (query) variables
    should be included during validation.

    .. warning::
        ``post_only`` applies to *where* the arguments to be
        validated come from. It does *not* restrict the form to
        only working with post, merely only checking POST vars.
``state``
    Passed through to FormEncode for use in validators that utilize
    a state object.
``on_get``
    Whether to validate on GET requests. By default only POST
    requests are validated.

Example::

    class SomeController(BaseController):

        def create(self, id):
            return render('/myform.mako')

        @validate(schema=model.forms.myshema(), form='create')
        def update(self, id):
            # Do something with self.form_result
            pass

"""
于 2013-02-07T21:00:42.997 回答