可选参数如何变成必需参数?
How can an optional parameter become required?
基于(以及我自己的回答),我在使用带有可选参数的函数时遇到了问题,例如在这个最小示例中:
import types
def noglobal(f):
return types.FunctionType(f.__code__, {})
@noglobal
def myFunction(x=0):
pass
myFunction()
基本上,它是这样失败的:
Traceback (most recent call last):
File "SetTagValue.py", line 10, in <module>
myFunction()
TypeError: myFunction() missing 1 required positional argument: 'x'
为什么 x
突然被视为必需参数?
如果您想保留默认参数值,您还需要传递它们:
import types
def noglobal(f):
return types.FunctionType(f.__code__, {}, f.__name__, f.__defaults__)
@noglobal
def myFunction(x=0):
pass
myFunction()
您可以将最后一个 closure
参数传递给 types.FunctionType
,如果您想让带有闭包的函数继续工作,您可能还想从 f.__closure__
继承它。
这是因为你没有正确复制函数。如果你看一下 types.FunctionType
的签名,你会发现它接受 5 个参数:
class function(object)
| function(code, globals, name=None, argdefs=None, closure=None)
|
| Create a function object.
|
| code
| a code object
| globals
| the globals dictionary
| name
| a string that overrides the name from the code object
| argdefs
| a tuple that specifies the default argument values
| closure
| a tuple that supplies the bindings for free variables
您没有传递任何参数 argdefs
,因此该函数不再有可选参数。复制函数的正确方法是
types.FunctionType(f.__code__,
{},
f.__name__,
f.__defaults__,
f.__closure__
)
但是,这会导致另一个问题:切断对全局变量的访问也会切断对内置函数的访问。如果您尝试在 myFunction
中使用 print
或 open
或 dict
或类似的东西,您将得到 NameError
。所以 真正 编写装饰器的正确方法是这样的:
import builtins
import types
def noglobal(f):
return types.FunctionType(f.__code__,
{'__builtins__': builtins},
f.__name__,
f.__defaults__,
f.__closure__
)
基于
import types
def noglobal(f):
return types.FunctionType(f.__code__, {})
@noglobal
def myFunction(x=0):
pass
myFunction()
基本上,它是这样失败的:
Traceback (most recent call last):
File "SetTagValue.py", line 10, in <module>
myFunction()
TypeError: myFunction() missing 1 required positional argument: 'x'
为什么 x
突然被视为必需参数?
如果您想保留默认参数值,您还需要传递它们:
import types
def noglobal(f):
return types.FunctionType(f.__code__, {}, f.__name__, f.__defaults__)
@noglobal
def myFunction(x=0):
pass
myFunction()
您可以将最后一个 closure
参数传递给 types.FunctionType
,如果您想让带有闭包的函数继续工作,您可能还想从 f.__closure__
继承它。
这是因为你没有正确复制函数。如果你看一下 types.FunctionType
的签名,你会发现它接受 5 个参数:
class function(object)
| function(code, globals, name=None, argdefs=None, closure=None)
|
| Create a function object.
|
| code
| a code object
| globals
| the globals dictionary
| name
| a string that overrides the name from the code object
| argdefs
| a tuple that specifies the default argument values
| closure
| a tuple that supplies the bindings for free variables
您没有传递任何参数 argdefs
,因此该函数不再有可选参数。复制函数的正确方法是
types.FunctionType(f.__code__,
{},
f.__name__,
f.__defaults__,
f.__closure__
)
但是,这会导致另一个问题:切断对全局变量的访问也会切断对内置函数的访问。如果您尝试在 myFunction
中使用 print
或 open
或 dict
或类似的东西,您将得到 NameError
。所以 真正 编写装饰器的正确方法是这样的:
import builtins
import types
def noglobal(f):
return types.FunctionType(f.__code__,
{'__builtins__': builtins},
f.__name__,
f.__defaults__,
f.__closure__
)