當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


Python NetworkX argmap用法及代碼示例

本文簡要介紹 networkx.utils.decorators.argmap 的用法。

用法:

class argmap(func, *args, try_finally=False)

在調用函數之前將映射應用於參數的裝飾器

此類提供了一個裝飾器,用於在調用函數之前映射(轉換)函數的參數。因此,例如,我們在許多函數中都有類似的代碼來確定參數是要創建的節點數還是要處理的節點列表。裝飾器提供了代碼來接受任何一個 - 在調用實際函數之前將指示的參數轉換為節點列表。

這個裝飾器類允許我們處理單個或多個參數。要處理的參數可以通過字符串指定,命名參數,也可以通過索引指定參數列表中的項目。

參數

func可調用的

應用於參數的函數

*args可迭代的(int、str 或 tuple)

參數列表,指定為字符串(它們的名稱)、整數(數字索引)或元組,其中可能包含整數、字符串和(遞歸)元組。每個都指示裝飾器應該映射哪些參數。元組表示 map 函數以相同的順序和嵌套結構接受(並返回)多個參數,如此處所示。

try_finally布爾(默認值:假)

如果為 True,則將函數調用包裝在 try-finally 塊中,並使用由 func 創建的 finally 塊的代碼。當映射函數構造一個需要後處理(如關閉)的對象(如文件句柄)時使用此函數。

注意

此類的對象是可調用的,並且旨在在定義裝飾器時使用。通常,裝飾器將函數作為輸入並構造函數作為輸出。具體來說,argmap 對象返回裝飾/包裝的輸入函數,以便在調用裝飾函數之前將指定的參數映射(轉換)為新值。

作為概述,argmap 對象返回一個新函數,其中包含原始函數的所有 dunder 值(如 __doc__ __name__ 等)。這個修飾函數的代碼是基於原始函數的簽名構建的。它首先將輸入參數映射到潛在的新值。然後它用這些新值調用修飾函數來代替已映射的指定參數。然後返回原始函數的返回值。這個新函數是用戶實際調用的函數。

提供了三個附加函數。

1)代碼是懶惰編譯的。也就是說,新函數在沒有編譯代碼的情況下作為對象返回,但包含所有需要的信息,因此可以在第一次調用時對其進行編譯。這樣可以節省導入時間,但會在第一次調用函數時增加額外的時間。隨後的調用與正常一樣快。

2) 如果 “try_finally” 僅關鍵字參數為 True,則在每個映射的參數之後有一個 try 塊,在包裝調用的另一側匹配,由一個 finally 塊關閉該映射。我們期望 func 返回一個 2 元組:映射的值和在 finally 子句中調用的函數。包含此函數,因此 open_file 裝飾器可以為裝飾函數提供文件句柄並在函數調用後關閉文件句柄。它甚至根據是否必須打開文件或輸入已經打開來跟蹤是否關閉文件句柄。因此,裝飾函數不需要包含任何代碼來打開或關閉文件。

3) 應用的映射可以處理多個參數。例如,您可以使用映射交換兩個參數,或將它們轉換為它們的和和它們的差。這是為了允許 quality.py 模塊中的裝飾器檢查輸入 partition 是否是輸入圖 G 的節點的有效分區。在此示例中,Map具有輸入 (G, partition) 。檢查有效分區後,映射或者引發異常,或者保持輸入不變。因此,許多進行此檢查的函數可以使用裝飾器,而不是將檢查代碼複製到每個函數中。下麵說明更複雜的嵌套參數結構。

其餘的注釋從廣義上說明了這個類的代碼結構和方法,以幫助理解如何使用它。

實例化 argmap 對象僅存儲映射函數和要映射的參數的輸入標識符。生成的裝飾器已準備好使用此映射來裝飾任何函數。調用該對象( argmap.__call__ ,但通常通過 @my_decorator 完成)會構造一個延遲編譯的修飾函數的瘦包裝器,並使用必要的函數屬性(如 __doc__ __name__ )進行包裝。該薄包裝函數作為修飾函數返回。當調用該修飾函數時,代碼的精簡包裝器將調用 argmap._lazy_compile 來編譯修飾函數(使用 argmap.compile ),並用新編譯的代碼替換精簡包裝器的代碼。這節省了每次導入 networkx 時的編譯步驟,但代價是在第一次調用修飾函數時進行編譯。

編譯修飾函數時,使用 argmap.assemble 方法遞歸匯編代碼。在嵌套裝飾器的情況下需要遞歸性質。組裝的結果是許多有用的對象。

sig原始裝飾函數的函數簽名為

argmap.signature() 構造。這是使用 inspect.signature 構造的,但使用屬性字符串 sig_defsig_call 以及特定於此函數的映射參數的其他信息進行了增強。此信息用於構造定義新修飾函數的代碼字符串。

wrapped_name由 argmap 構造的唯一內部使用的名稱

用於裝飾函數。

職能this 代碼中使用的函數的字典

裝飾函數,在 exec 中用作 globals 。這個字典被遞歸更新以允許嵌套裝飾。

Map塊映射傳入參數的代碼(作為字符串列表)

值到它們的映射值。

最後提供可能嵌套的代碼(作為字符串列表)

如果需要,一組 finally 子句。

mutable_args一個布爾值,指示 sig.args 元組是否應該是

轉換為列表,因此可以發生突變。

在此遞歸匯編過程之後, argmap.compile 方法構造代碼(作為字符串)以在需要時將元組 sig.args 轉換為列表。它使用適當的縮進加入定義代碼並編譯結果。最後,評估此代碼並將原始包裝器的實現替換為編譯版本(有關更多詳細信息,請參見argmap._lazy_compile)。

其他 argmap 方法包括 _name_count,它們允許內部生成的名稱在 python 會話中是唯一的。方法 _flatten_indent 將嵌套的字符串列表處理為正確縮進的 python 代碼,準備進行編譯。

盡管通常不使用更複雜的嵌套參數元組,但也允許使用。對於簡單的 2 參數情況,argmap 輸入 (“a”, “b”) 意味著映射函數將采用 2 個參數並返回映射值的 2 元組。使用 argmap 輸入 ("a", ("b", "c")) 的更複雜示例要求映射函數采用 2 個輸入,第二個是 2 元組。然後它必須在同一個嵌套結構 (newa, (newb, newc)) 中輸出 3 個映射值。這種通用性通常不需要,但在處理多個參數時很方便實現。

例子

這些示例中的大多數都使用 @argmap(...) 將裝飾器應用到下一行定義的函數。然而,在 NetworkX 代碼庫中,argmap 在函數中使用來構造裝飾器。也就是說,裝飾器定義一個映射函數,然後使用argmap構建並返回一個裝飾函數。一個簡單的例子是一個裝飾器,它指定要報告貨幣的貨幣。裝飾器(名為 convert_to )的用法如下:

@convert_to("US_Dollars", "income")
def show_me_the_money(name, income):
    print(f"{name} : {income}")

創建裝飾器的代碼可能是:

def convert_to(currency, which_arg):
    def _convert(amount):
        if amount.currency != currency:
            amount = amount.to_currency(currency)
        return amount
    return argmap(_convert, which_arg)

盡管 argmap 有這個常見的習慣用法,但以下大多數示例都使用 @argmap(...) 習慣用法來節省空間。

這是使用 argmap 對兩個函數參數的元素求和的示例。裝飾函數:

@argmap(sum, "xlist", "zlist")
def foo(xlist, y, zlist):
    return xlist - y + zlist

是語法糖:

def foo(xlist, y, zlist):
    x = sum(xlist)
    z = sum(zlist)
    return x - y + z

並且等效於(使用參數索引):

@argmap(sum, "xlist", 2)
def foo(xlist, y, zlist):
    return xlist - y + zlist

或者:

@argmap(sum, "zlist", 0)
def foo(xlist, y, zlist):
    return xlist - y + zlist

轉換函數可以應用於多個參數,例如:

def swap(x, y):
    return y, x

# the 2-tuple tells argmap that the map `swap` has 2 inputs/outputs.
@argmap(swap, ("a", "b")):
def foo(a, b, c):
    return a / b * c

相當於:

def foo(a, b, c):
    a, b = swap(a, b)
    return a / b * c

更一般地,應用的參數可以是字符串或整數的嵌套元組。語法 @argmap(some_func, ("a", ("b", "c"))) 預計 some_func 接受 2 個輸入,第二個輸入預計為 2 元組。然後它應該返回 2 個輸出,第二個輸出是 2 元組。返回值將分別替換輸入“a”、“b”和“c”。對於@argmap(some_func, (0, ("b", 2))) 也是如此。

另外,請注意,對於可變參數函數,允許使用大於命名參數數量的索引。例如:

def double(a):
    return 2 * a

@argmap(double, 3)
def overflow(a, *args):
    return a, args

print(overflow(1, 2, 3, 4, 5, 6))  # output is 1, (2, 3, 8, 5, 6)

最後嘗試

此外,這個 argmap 類可用於創建一個啟動 try…finally 塊的裝飾器。必須編寫裝飾器以返回轉換後的參數和結束函數。包含此函數是為了啟用 open_file 裝飾器,該裝飾器可能需要關閉文件,具體取決於是否必須打開該文件。此函數使用 @argmap 的僅關鍵字 try_finally 參數。

例如,此Map打開一個文件,然後確保它已關閉:

def open_file(fn):
    f = open(fn)
    return f, lambda: f.close()

裝飾器將其應用於函數 foo

@argmap(open_file, "file", try_finally=True)
def foo(file):
    print(file.read())

是語法糖:

def foo(file):
    file, close_file = open_file(file)
    try:
        print(file.read())
    finally:
        close_file()

並且等效於(使用索引):

@argmap(open_file, 0, try_finally=True)
def foo(file):
    print(file.read())

以下是用於創建裝飾器的try_finally 函數示例:

def my_closing_decorator(which_arg):
    def _opener(path):
        if path is None:
            path = open(path)
            fclose = path.close
        else:
            # assume `path` handles the closing
            fclose = lambda: None
        return path, fclose
    return argmap(_opener, which_arg, try_finally=True)

然後可以用作:

@my_closing_decorator("file")
def fancy_reader(file=None):
    # this code doesn't need to worry about closing the file
    print(file.read())

相關用法


注:本文由純淨天空篩選整理自networkx.org大神的英文原創作品 networkx.utils.decorators.argmap。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。