[英]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
)。
一个不限制f
和g
的定义顺序的选项,如果动态更改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
但这是一个非常具体的案例:
通用解决方案需要相当多的代码,但允许任何签名合并到另一个,例如:
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.