本功能中的Python函数装饰

时间:2014-01-29 16:07:10

标签: python

def images_custom_list(args, producer_data):
    tenant, token, url = producer_data
    url = url.replace(".images", ".servers")

    url = url + '/' + 'detail'
    output = do_request(url, token)
    output = output[0].json()["images"]
    custom_images_list = [custom_images for custom_images in output 
            if custom_images["metadata"].get('user_id', None)]
    temp_image_list = []
    for image in custom_images_list:
        image_temp  = ( { "status": image["status"], 
            "links": image["links"][0]["href"], 
            "id": image["id"], "name": image["name"]} )
        temp_image_list.append(image_temp)
    print json.dumps(temp_image_list, indent=2)

def image_list_detail(args, producer_data):
    tenant, token, url = producer_data
    url = url.replace(".images", ".servers")

    uuid = args['uuid']
    url = url + "/" + uuid
    output = do_request(url, token)
    print output[0]

我试图通过利用Python的功能装饰使代码更高效,更干净。由于这两个函数共享相同的前两行,我怎么能用这两行创建一个函数修饰器并将这两个函数装饰好呢?

2 个答案:

答案 0 :(得分:2)

这是一种解决方法:

from functools import wraps

def fix_url(function):
    @wraps(function)
    def wrapper(*args, **kwarg):
        kwarg['url'] = kwarg['url'].replace(".images", ".servers")
        return function(*args, **kwarg)
    return wrapper

@fix_url
def images_custom_list(args, tenant=None, token=None, url=None):
    url = url + '/' + 'detail'
    output = do_request(url, token)
    output = output[0].json()["images"]
    custom_images_list = [custom_images for custom_images in output 
            if custom_images["metadata"].get('user_id', None)]
    temp_image_list = []
    for image in custom_images_list:
        image_temp  = ( { "status": image["status"], 
            "links": image["links"][0]["href"], 
            "id": image["id"], "name": image["name"]} )
        temp_image_list.append(image_temp)
    print json.dumps(temp_image_list, indent=2)

@fix_url
def image_list_detail(args, tenant=None, token=None, url=None):
    uuid = args['uuid']
    url = url + "/" + uuid
    output = do_request(url, token)
    print output[0]

遗憾的是,您可能会注意到您需要摆脱producer_data,但是将它拆分为多个参数,因为您无法分解代码的这一部分,因为您无论如何都需要再次拆分它在每个功能中。我选择使用关键字参数(通过将默认值设置为None),但您也可以使用位置参数,即调用。

顺便说一句,请注意,这并没有使代码更有效率,尽管它有助于使代码更具可读性(您知道这两种方法都以相同的方式更改URL,并且当您修改URL更改部分时,它在所有地方以相同的方式完成),但每次调用函数时它会再进行2次函数调用,因此它不会更“高效”。

N.B。:它基本上是基于@ joel-cornett的例子(我不会使用@wraps,只是普通的旧双功能装饰器),我只是专门用它。 (我认为他不值得-1) 请至少+1他的回答或接受。

但我认为更简单的方法是:

def fix_url(producer_data):
    return (producer_data[0], producer_data[1], producer_data[2].replace(".images", ".servers"))

def images_custom_list(args, producer_data):
    tenant, token, url = fix_url(producer_data)

    # stuff ...

def image_list_detail(args, producer_data):
    tenant, token, url = fix_url(producer_data)

    # stuff ...

使用更简单的语法(没有装饰器),只进行一次函数调用。

答案 1 :(得分:1)

像这样:

from functools import wraps

def my_timesaving_decorator(function):
    @wraps(function)
    def wrapper(*args, **kwargs):
        execute_code_common_to_multiple_function()

        #Now, call the "unique" code
        #Make sure that if you modified the function args,
        #you pass the modified args here, not the original ones.
        return function(*args, **kwargs)

    return wrapper