跳转到主要内容

关键字参数跟踪 !!

项目描述

星星星星 ✨ ✨

pypi tests docs License

终于!Python中的可变关键字跟踪。

因为这让我很伤心

def main(**kw):
    function_with_a_bunchhhh_of_arguments(**kw)  # I only want to pass some of **kw !!
    another_function_with_a_bunchhhh_of_arguments(**kw)  # and put the other half here !!!

# hmmm let's see what can I pass to this function...
help(main)  # main(**kw)
# HALP????? aljdsflaksjdflkasjd

😖😭😭

为什么我们不能有:🧞‍♀️ 🧚🏻‍♀️ ✨ ✨

import starstar

def function_a(a=1, b=2, c=3): ...
def function_b(x=8, y=9, z=10): ...

@starstar.traceto(function_a, function_b)
def main(**kw):
    kw_a, kw_b = starstar.divide(kw, function_a, function_b)
    function_a(**kw_a)  # gets: a, b, c
    function_b(**kw_b)  # gets: x, y, z

# hmmm let's see what can I pass to this function...
help(main)  # main(a=1, b=2, c=3, x=8, y=9, z=10)
# yayyyy!!!

😇🥰🌈

  • 不喜欢重复函数参数及其默认值,因此经常使用 **kwargs 吗?
  • 有时需要将 **kwargs 传递给多个函数,但讨厌需要列举除一个函数外的所有参数?
  • 希望Python可以自己看看并为你解决这个问题?

starstar试图在保持您函数信息可查的同时,弥合优雅、简洁和紧凑的代码(DRY!永远!<3)之间的差距。

它还试图通过最小化添加到实际函数调用中的开销和尽量减少使用包装函数来尽可能高效地完成内部操作。

它可以

  • 查看函数签名并使用描述的参数将kwargs排序到每个函数的单独字典中。(divide(kw, *funcs)
  • 修改函数的签名以包括它包装的其它函数的参数,并将其**kwargs发送到这些函数。(traceto(*funcs)
  • 执行functools.wraps,同时也在签名中保留包装函数的任何参数(wraps(func)(wrapper)

我真心希望你会觉得这很有用!如果你有任何请求/建议,请随时提出,因为我希望你也喜欢它!

安装

pip install starstar

用法

将参数传递给多个函数!

我们有一个函数,它想要将参数传递给两个不同的函数,而无需在该函数中列举这些参数。

import starstar

def func_a(a=None, b=None, c=None):
    return a, b, c

def func_b(d=None, e=None, f=None):
    return d, e, f

def main(**kw):
    kw_a, kw_b = starstar.divide(kw, func_a, func_b)
    func_a(**kw_a)
    func_b(**kw_b)

将参数传递给多层级的多个函数!

在这里,我们将参数向下传递两级,将 func_afunc_b 的参数拆分到第一个字典中,将 func_d 的参数拆分到第二个字典中。

def func_c(**kw):
    kw_a, kw_b = starstar.divide(kw, func_a, func_b)
    func_a(**kw_a)
    func_b(**kw_b)

def func_d(g=None, h=None, i=None):
    return g, h, i

def main(**kw):
    kw_c, kw_d = starstar.divide(kw, (func_a, func_b), func_d)  # combine multiple functions into one kw dict
    func_c(**kw_c)
    func_d(**kw_d)

但是,我们可以让这个过程更简单!这里我们修改了 func_c 的签名,使其参数发送到 func_afunc_b

@starstar.traceto(func_a, func_b)
def func_c(**kw):
    kw_a, kw_b = starstar.divide(kw, func_a, func_b)
    func_a(**kw_a)
    func_b(**kw_b)

@starstar.traceto(func_c, func_d)
def main(**kw):
    kw_c, kw_d = starstar.divide(kw, func_c, func_d)
    func_c(**kw_c)
    func_d(**kw_d)

结果如下签名

import inspect
print(inspect.signature(func_c))
print(inspect.signature(main))
# (a=None, b=None, c=None, d=None, e=None, f=None)
# (a=None, b=None, c=None, d=None, e=None, f=None, g=None, h=None, i=None)

额外奖励

functools.wraps,但更好

内置的 functools.wraps 不考虑 inner 的参数,因此包装的签名不知道它们,这可能对依赖于准确签名的任何工具都是误导性的。

import functools

def deco(func):
    @functools.wraps(func)
    def inner(q, *a, **kw):
        return q, func(*a, **kw)
    return inner

@deco
def asdf(x, y, z):
    pass

import inspect
print(inspect.signature(asdf))  # (x, y, z)

但现在它可以了!

import starstar

def deco(func):
    @starstar.wraps(func)
    def inner(q, *a, **kw):
        return q, func(*a, **kw)
    return inner

@deco
def asdf(x, y, z):
    pass

import inspect
print(inspect.signature(asdf))  # (q, x, y, z)

并且如果你想要跳过某些已经由包装器提供的位置参数或命名参数。

import starstar

def deco(func):
    @starstar.wraps(func, skip_n=2, skip_args=('blah',))
    def inner(q, *a, **kw):
        return q, func(1, 2, *a, blah=17, **kw)
    return inner

覆盖函数默认值

比如说,我们想要更改函数的默认参数(例如,我们想要将配置卸载到 yaml 配置文件中)。

import starstar

@starstar.defaults
def func_x(x, y=6):
    return x, y

import inspect
print(inspect.signature(func_x))  # <Signature (x, y=6)>

assert func_x(5) == 11
func_x.update(y=7)
assert func_x(5) == 12

import inspect
print(inspect.signature(func_x))  # <Signature (x, y=17)>
import yaml

with open(config_file, 'r') as f:
    config = yaml.load(f)

func_x.update(**(config.get('func_x') or {}))

未来展望

  • 跟踪位置参数?经过一番思考,这似乎很麻烦,因为我不确定我们如何处理 kwargs 之间的名称冲突。
  • traceto 允许跳过?
  • 关于关键字名称冲突有一个更具体的计划。

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源代码分布

starstar-0.6.1.tar.gz (33.8 kB 查看哈希值)

上传时间 源代码

由...