2010-08-31 30 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)