[英]How to pass an empty parameter to a python function?
Here is the working code: 这是工作代码:
def g(y=10):
return y**2
def f(x,y=10):
return x*g(y)
print(f(5)) #->500
However, let's suppose we don't want to remember and copy a default value of keyword parameter y
to the definition of external function (especially if there are several layers of external functions). 但是,我们假设我们不想记住并将关键字参数y
的默认值复制到外部函数的定义中(特别是如果有多个外部函数层)。 In the above example it means that we want to use parameter, already defined in g
. 在上面的例子中,它意味着我们想要使用已在g
定义的参数。
One way to do that: 一种方法:
def f(x,y=None):
if y==None: return x*g()
else: return x*g(y)
But is there a cleaner way to do the same? 但有没有更清洁的方法来做同样的事情? Something like: 就像是:
def f(x,y=empty()):
return x*g(y)
This is possible : 这是可能的 :
def g(y=10):
return y**2
def f(x, y=g.__defaults__[0]):
return x * g(y)
But it is arguably less clear than what you had originally (defaulting y
to None
). 但它可以说比你原来的不那么清楚 (将y
默认为None
)。
An option which doesn't restrict the definition order of f
and g
, and should remain working if the function default of g
gets changed dynamically: 一个不限制f
和g
的定义顺序的选项,如果动态更改g
的函数默认值,它应该保持工作:
def f(x, y=None):
kwargs = {}
if y is None:
kwargs['y'] = y
return x * g(**kwargs)
Interesting question! 有趣的问题! Here's another possibility, however this requires handing in the second parameter as a named parameter. 这是另一种可能性,但是这需要将第二个参数作为命名参数。
>>> def g(y=10):
... return y**2
...
>>> def f(x, **kwargs):
... return x * g(**kwargs)
...
>>> f(5)
500
>>> f(5, y=0)
0
A limitation of signatures such as def f(x, y=None)
or def f(x, **kwargs)
is that readers have to dig into source code or documentation to find out what's going on with y
. def f(x, y=None)
或def f(x, **kwargs)
等签名的限制是读者必须深入研究源代码或文档以找出y
发生了什么。 Stick to something simple and straightforward: 坚持简单明了的事情:
DEFAULT_Y = 10
def g(y=DEFAULT_Y): ...
def f(x, y=DEFAULT_Y): ...
I'd like to start by saying if the arguments were keyword only this would be so easy: 我想首先说一下,如果参数只是关键字, 那么这将是如此简单:
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()
if you are using positional arguments it isn't quite as easy although your example is one of the specific cases that works the same way: 如果你使用位置参数,它并不是那么容易,尽管你的例子是以相同方式工作的特定情况之一:
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
But this is a very specific case: 但这是一个非常具体的案例:
The generic solution requires quite a bit of code but allows any signature to be merged into another, for example: 通用解决方案需要相当多的代码,但允许任何签名合并到另一个,例如:
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)>
This can be achieved with the following code (I can't find a simpler way to do it that works with above case) 这可以通过以下代码实现(我无法找到一种更简单的方法来处理上述情况)
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
If you can modify g
, then this works: 如果你可以修改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.