networkx.utils.decorators.argmap#

class argmap(func, *args, try_finally=False)[源代码]#

在调用函数之前将映射应用于参数的修饰符

此类提供了一个修饰符,用于在调用函数之前映射(转换)函数的参数。因此,例如,我们在许多函数中都有类似的代码来确定参数是要创建的节点数,还是要处理的节点列表。修饰器提供了接受其中任何一个的代码--在调用实际函数之前将指定的参数转换为节点列表。

这个修饰符类允许我们处理单个或多个参数。要处理的参数可以通过命名参数的字符串来指定,也可以通过索引来指定参数列表中的项。

参数
func可调用

要应用于参数的函数

*args可迭代的(整型、字符串或元组)

参数列表,指定为字符串(其名称)、整数(数值索引)或元组,其中可能包含整数、字符串和(递归)元组。每个参数都指示装饰器应该映射哪些参数。元组表示map函数以相同的顺序和嵌套结构获取(并返回)多个参数,如下所示。

try_finally布尔值(默认值:FALSE)

如果为True,则使用由创建的Finally块的代码将函数调用包装在Try-Finally块中 func 。这在map函数构造需要后处理(如关闭)的对象(如文件句柄)时使用。

参见

not_implemented_for
open_file
nodes_or_number
random_state
py_random_state
networkx.community.quality.require_partition
require_partition

笔记

此类的对象是可调用的,并打算在定义修饰符时使用。通常,装饰者将函数作为输入,并构造函数作为输出。具体地说,一个 argmap 对象返回经过修饰/包装的输入函数,以便在调用经过修饰的函数之前将指定的参数映射(转换)为新值。

总而言之,argmap对象返回一个新函数,其中包含原始函数的所有DUnder值(如 __doc__, `_ _名称__`等)。此修饰函数的代码是基于原始函数的签名构建的。它首先将输入参数映射到可能的新值。然后,它使用这些新值来调用修饰函数,而不是已映射的指定参数。然后返回原始函数的返回值。这个新函数是用户实际调用的函数。

它还提供了三个附加功能。

1)代码编译迟缓。也就是说,新函数在没有编译代码的情况下作为对象返回,但带有所有需要的信息,以便可以在第一次调用时进行编译。这节省了导入时的时间,但代价是第一次调用函数时需要额外的时间。然后,随后的呼叫就会像正常一样快。

2)如果仅限关键字的参数为True,则在包装调用的另一端匹配的每个映射参数后面都有一个try块,最后一个块关闭该映射。我们希望func返回一个二元组:映射值和将在Finally子句中调用的函数。此功能包括在内,因此 open_file 修饰器可以为修饰的函数提供文件句柄,并在函数调用后关闭文件句柄。它甚至根据它是必须打开文件还是输入已经打开来跟踪是否关闭文件句柄。因此,修饰后的函数不需要包含打开或关闭文件的任何代码。

3)应用的映射可以处理多个参数。例如,您可以使用映射交换两个参数,或将它们转换为它们的总和及其差异。包括这一点是为了让装饰师在 quality.py 检查输入的模块 partition 是输入图的节点的有效分区 G 。在本例中,地图具有输入 (G, partition) 。在检查有效分区之后,映射要么引发异常,要么保持输入不变。因此,许多进行此检查的函数都可以使用修饰符,而不是将检查代码复制到每个函数中。下面将描述更复杂的嵌套参数结构。

其余的注释概括地描述了该类的代码结构和方法,以帮助理解如何使用它。

实例化一个 argmap object simply stores the mapping function and the input identifiers of which arguments to map. The resulting decorator is ready to use this map to decorate any function. Calling that object (argmap.__call__, but usually done via @my_decorator) a lazily compiled thin wrapper of the decorated function is constructed, wrapped with the necessary function dunder attributes like _ _DOC__`和 `__name__ 。该薄包装函数作为修饰后的函数返回。当调用该修饰函数时,代码的瘦包装调用 argmap._lazy_compile 它编译修饰后的函数(使用 argmap.compile ),并用新编译的代码替换薄包装器的代码。这节省了每次导入networkx的编译步骤,代价是在第一次调用修饰函数时进行编译。

编译修饰函数时,使用 argmap.assemble 方法。在使用嵌套修饰符的情况下,需要使用递归性质。组装的结果是许多有用的对象。

西格原始修饰函数的函数签名为

构造者 argmap.signature() 。这是使用以下工具构建的 inspect.signature 但使用属性字符串进行了增强 sig_defsig_call ,以及特定于此函数的映射参数的其他信息。此信息用于构造定义新修饰函数的代码字符串。

wrapped_name由argmap构造的唯一内部使用的名称

用于装饰的函数。

功能的代码中使用的函数的字典

装饰函数,用作 globals 在……里面 exec 。此字典以递归方式更新以允许嵌套修饰。

地图块映射传入参数的代码(作为字符串列表)

值设置为其映射值。

最终获奖代码(作为字符串列表)以提供可能嵌套的

如果需要,一组Finally子句。

Mutable_args:一个布尔值,指示 sig.args 元组应为一个布尔值,指示

已转换为列表,因此可以发生突变。

在此递归汇编过程之后, argmap.compile 方法构造代码(以字符串形式)以转换元组 sig.args 如果需要的话加到名单上。它用适当的缩进联接定义代码,并编译结果。最后,评估这段代码,并用编译后的版本替换原始包装器的实现(请参见 argmap._lazy_compile 了解更多详细信息)。

其他 argmap methods include _ 名称`和 `_count which allow internally generated names to be unique within a python session. The methods _ 展平`和 `_indent 将嵌套的字符串列表处理为缩进正确的Python代码,以便进行编译。

也允许使用更复杂的嵌套参数元组,尽管通常不会使用。对于简单的2个参数的情况,argmap输入(“a”,“b”)意味着映射函数将接受2个参数并返回映射值的2元组。使用argmap输入的一个更复杂的示例 ("a", ("b", "c")) 需要映射函数接受2个输入,其中第二个是2元组。然后,它必须在相同的嵌套结构中输出3个映射值 (newa, (newb, newc)) 。这种级别的通用性并不经常需要,但在处理多个参数时很容易实现。

实例

这些示例中的大多数使用 @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)

Try Finally

此外,这一点 argmap 类可用于创建启动Try...Finally块的装饰器。必须编写修饰符以返回转换后的参数和结束函数。包括此功能是为了支持 open_file 可能需要关闭文件的修饰器,具体取决于它是否必须打开该文件。此功能仅使用关键字 try_finally 参数为 @argmap

例如,此地图打开一个文件,然后确保它已关闭::

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())
__init__(func, *args, try_finally=False)[源代码]#

方法

assemble(f)

收集修饰函数包装f的源组件。

compile(f)

编译修饰后的函数。

signature(f)

构造描述以下内容的签名对象 f