代码之家  ›  专栏  ›  技术社区  ›  Will Dean

为Python函数参数提供额外装饰/元数据的好方法是什么?

  •  7
  • Will Dean  · 技术社区  · 14 年前

    我们正在考虑使用Python(IronPython,但我不认为这是相关的)为另一个应用程序提供某种“宏”支持,该应用程序控制一个设备。

    我们想用Python编写相当简单的函数,它需要一些参数,比如时间、温度和位置。不同的函数将采用不同的参数,主应用程序将包含用户界面(类似于属性网格),允许用户为Python函数参数提供值。

    例如,函数1可能需要一段时间和一个温度,而函数2可能需要一个位置和几次。

    然而,仅仅列出参数名称是不够的——理想情况下,我们希望能够包含关于每个参数的更多信息——例如,它是“类型”(高级类型-时间、温度等,而不是语言级别的类型),也许是“友好名称”或描述。

    我想到的两种可能性是:

    • 对参数使用严格的命名约定,然后从它们的名称推断出关于它们的信息(使用getargspec获取)

    因为Python似乎非常流行于将脚本构建到大型应用程序中,所以我认为这是一个解决了一些常见约定的问题,但是我还没有找到它们。

    4 回复  |  直到 14 年前
        1
  •  7
  •   nmichaels    14 年前

    decorator是向函数添加元数据的好方法。添加一个将类型列表附加到.params属性或其他内容的类型:

    def takes(*args):
        def _takes(fcn):
            fcn.params = args
            return fcn
        return _takes
    
    @takes("time", "temp", "time")
    def do_stuff(start_time, average_temp, stop_time):
        pass
    
        2
  •  4
  •   Tomasz Wysocki    14 年前

    我会用一些装饰物:

    class TypeProtector(object):
        def __init__(self, fun, types):
            self.fun, self.types = fun, types
        def __call__(self, *args, **kwargs)
            # validate args with self.types
            pass
            # run function
            return fun(*args, **kwargs)
    
    def types(*args):
        def decorator(fun):
            # validate args count with fun parameters count
            pass
            # return covered function
            return TypeProtector(fun, args)
        return decorator
    
    @types(Time, Temperature)
    def myfunction(foo, bar):
        pass
    
    myfunction('21:21', '32C')
    print myfunction.types
    
        3
  •  1
  •   leoluk    14 年前

    “蟒蛇式”的方法是 function annotations .

    def DoSomething(critical_temp: "temperature", time: "time")
        pass
    
        4
  •  0
  •   Uri Goren    7 年前

    对于python2.x,我喜欢使用docstring

    def my_func(txt):
        """{
        "name": "Justin",
        "age"   :15
        }"""
        pass
    

    并且它可以通过这个代码段自动分配给函数对象

    for f in globals():
        if not hasattr(globals()[f], '__call__'):
            continue
        try:
            meta = json.loads(globals()[f].__doc__)
        except:
            continue
        for k, v in meta.items():
            setattr(globals()[f], k, v)