2010-08-31 26 views
7

我们正在考虑使用Python(IronPython,但我认为这不相关)为另一个控制一台设备的应用程序提供了一种“宏”支持。为Python函数参数提供额外装饰/元数据的好方法是什么?

我们想用Python语言编写相当简单的功能,这需要几个参数 - 这些将是一样的东西时间和温度和位置。不同的函数需要不同的参数,主应用程序将包含用户界面(类似于属性网格),它允许用户为Python函数参数提供值。

因此,例如功能1可能需要一段时间和温度,以及函数2可能采取的位置和几次。

我们希望能够从Python代码中动态构建用户界面。很容易做的事情是在模块中找到函数列表,并使用inspect.getargspec来获取每个函数的参数列表。

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

所以,问题是,什么是将这种信息功能的好“Python化”的方式。

两种可能性我以为是:

  • 使用参数的严格的命名约定,然后从它们的名字推断出他们的东西(使用getargspec牵强)

  • 创造我们自己docstring元语言(可能比CSV稍微多一点)并使用文档字符串作为我们的元数据。

因为Python似乎为构建脚本到大型应用很受欢迎,我想这是一个解决的问题有一些共同的约定,但我一直没能找到他们。

+2

,您可以使用函数注释:http://www.python.org/dev/peps/pep-3107/ – unutbu 2010-08-31 16:25:26

+2

py.test使用您提到的为每个测试指定数据的第一种方法。他们的情况很好。 – 2010-08-31 16:27:03

回答

7

装饰都添加元数据功能的好方法。添加一个需要的类型列表追加到.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 
+4

考虑使用对象而不是字符串来描述类型: '@takes(Time,Temp,Time)'。字符串不是很好的方法,因为如果不修改核心就无法扩展该模型。此外,您的核心可以通过无状态(您不必注册类型名称)。你的对象应该知道如何呈现自己的HTML以及如何验证自己。你也有好处,你可以参数化你的类型: '@takes(Int(max = 100,min = 0))'。 – 2010-08-31 18:01:32

+0

是的,那。琴弦真的只是示范。当我过去这样做时,我使用接受字符串(我唯一的输入源)的函数和返回的程序可以使用的对象(有时在做数据库查找之后)。 – nmichaels 2010-08-31 18:34:17

4

我会用某种装饰的:

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 
+0

非常感谢 - 我希望我能给你所有'答案'。除了原来的问题,TypeProtector在这方面的作用是什么? – 2010-08-31 17:08:37

+2

即。您可以轻松检查功能是否装饰:isinstance(TypeProtector,o)。基本上直接像'fcn.params = args'一样修改函数对象,如果你想要一个干净的自解释代码,那么它不是那么好。 – 2010-08-31 17:37:52

1

的“Python化”的方式来做到这一点是function annotations

def DoSomething(critical_temp: "temperature", time: "time") 
    pass 
+1

2.6呢? – 2010-08-31 16:35:31

+0

为2.6,他可以使用你的一个 – leoluk 2010-08-31 16:41:23

+0

这是非常有趣的,因为它引导我成为几个有用的信息来源 - 不幸的是,由于版本问题,我不能在这个特定的项目上使用它,但我最终会当然 – 2010-08-31 17:09:28

0

对于Python 2.x中,我喜欢使用的文档字符串

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

,它可以如果您正在使用Python3被自动分配给功能对象与此片段

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)