繁体   English   中英

如何将空参数传递给python函数?

[英]How to pass an empty parameter to a python function?

这是工作代码:

def g(y=10):
    return y**2

def f(x,y=10):
    return x*g(y)

print(f(5)) #->500

但是,我们假设我们不想记住并将关键字参数y的默认值复制到外部函数的定义中(特别是如果有多个外部函数层)。 在上面的例子中,它意味着我们想要使用已在g定义的参数。

一种方法:

def f(x,y=None):
    if y==None: return x*g()
    else: return x*g(y)

但有没有更清洁的方法来做同样的事情? 就像是:

def f(x,y=empty()):
    return x*g(y)

这是可能的

def g(y=10):
    return y**2

def f(x, y=g.__defaults__[0]):
    return x * g(y)

但它可以说比你原来的不那么清楚 (将y默认为None )。

一个不限制fg的定义顺序的选项,如果动态更改g的函数默认值,它应该保持工作:

def f(x, y=None):
    kwargs = {}
    if y is None:
        kwargs['y'] = y
    return x * g(**kwargs)

有趣的问题! 这是另一种可能性,但是这需要将第二个参数作为命名参数。

>>> def g(y=10):
...     return y**2
... 
>>> def f(x, **kwargs):
...     return x * g(**kwargs)
... 
>>> f(5)
500
>>> f(5, y=0)
0

def f(x, y=None)def f(x, **kwargs)等签名的限制是读者必须深入研究源代码或文档以找出y发生了什么。 坚持简单明了的事情:

DEFAULT_Y = 10
def g(y=DEFAULT_Y): ...
def f(x, y=DEFAULT_Y): ...

我想首先说一下,如果参数只是关键字, 那么这将是如此简单:

def f(*, x="x", y= "y",z="z"):
    print(x,y,z)

def g(*, x,y,z):
    print(x,y,z,"from g!!")

if g.__kwdefaults__ is None: #completely override defaults
    g.__kwdefaults__ = f.__kwdefaults__
else: #if there are already some defaults then update
    g.__kwdefaults__.update(f.__kedefaults__)

g()

如果你使用位置参数,它并不是那么容易,尽管你的例子是以相同方式工作的特定情况之一:

def g(y=10): #last argument is y
    return y**2

def f(x,y): #last argument is y
    return x*g(y)
f.__defaults__ = g.__defaults__ #copies the end of the defaults to f

print(f(5)) #->500

但这是一个非常具体的案例:

  1. 继承默认值的参数必须与原始参数的顺序相同。
  2. 在具有继承默认值的参数之后,不得有任何位置参数
  3. 一定不能有任何其他参数的默认值(或它们被覆盖)

通用解决方案需要相当多的代码,但允许任何签名合并到另一个,例如:

def f(x,y,z=0,reverse=True):
    pass

@copy_defaults(f)
def g(a,b, #arguments for g
      x,y,z, #arguments to forward to f
      c=None, d="test", #some optional arguments for g
      *,reverse): #only take reverse as a keyword
    pass

>>> inspect.signature(g)
<Signature (a, b, x, y, z=0, c=None, d='test', *, reverse=True)>

这可以通过以下代码实现(我无法找到一种更简单的方法来处理上述情况)

import inspect

def copy_defaults(original_f):
    "creates wrapper for DefaultArgs(original_f).copy_defaults(dest_f)"
    def wrapper(dest_f):
        return DefaultArgs(original_f).copy_defaults(dest_f)
    return wrapper

class DefaultArgs(dict):
    def __init__(self,func):
        spec = inspect.getfullargspec(func)
        if spec.defaults:
            dict.__init__(self,
                          zip(reversed(spec.args),
                              reversed(spec.defaults)
                          ))
        else:
            dict.__init__(self) #I'm not sure this is necessary
        if spec.kwonlydefaults:
            self.update(spec.kwonlydefaults)

    def get_kwdefaults(self,keywords):
        return {k:v for k,v in self.items() if k in keywords}

    def gen_pos_defaults(self,args,defaults=None):
        if defaults is None:
            defaults = ()
        found_default = False
        for i,arg in enumerate(args,start=len(defaults)-len(args)):
            if arg in self:
                yield self[arg]
                found_default = True
            elif i>=0:
                yield defaults[i]
            elif found_default: #if an argument does not have a default but is after one that does
                raise TypeError("non-default argument %r follows default argument"%arg)

    def copy_defaults(self,func):
        spec = inspect.getfullargspec(func)
        new_kwargs = self.get_kwdefaults(spec.kwonlyargs)
        if func.__kwdefaults__ is not None:
            func.__kwdefaults__.update(new_kwargs)
        else:
            func.__kwdefaults__ = new_kwargs

        func.__defaults__ = tuple(self.gen_pos_defaults(spec.args,spec.defaults))
        return func

如果你可以修改g ,那么这有效:

def g(y=None):
    if y is None:
        y = 10
    return y**2

def f(x,y=None):
    return x*g(y)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM