如何将空参数传递给python函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36650583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to pass an empty parameter to a python function?
提问by Nik
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). In the above example it means that we want to use parameter, already defined in g
.
但是,假设我们不想记住并将关键字参数的默认值复制y
到外部函数的定义中(特别是如果有多层外部函数时)。在上面的例子中,这意味着我们要使用已经在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)
回答by dorian
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
回答by wim
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 clearthan 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
and的定义顺序的选项,g
如果g
动态更改函数默认值,则应保持工作状态:
def f(x, y=None):
kwargs = {}
if y is None:
kwargs['y'] = y
return x * g(**kwargs)
回答by Alex Hall
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
. Stick to something simple and straightforward:
诸如def f(x, y=None)
或之类的签名的局限性def f(x, **kwargs)
在于,读者必须深入研究源代码或文档才能了解y
. 坚持简单明了的事情:
DEFAULT_Y = 10
def g(y=DEFAULT_Y): ...
def f(x, y=DEFAULT_Y): ...
回答by Tadhg McDonald-Jensen
I'd like to start by saying if the arguments were keyword only this would be soeasy:
我想首先说如果参数是关键字,这将非常简单:
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 arguments to inherit the defaults must be in the same order as the original.
- There must not be any positional arguments after the ones with inherited defaults
- There must not be any other arguments with default values (or they get overridden)
- 继承默认值的参数必须与原始参数的顺序相同。
- 在具有继承默认值的参数之后不能有任何位置参数
- 不能有任何其他带有默认值的参数(否则它们会被覆盖)
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
回答by BallpointBen
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)