问题
Based on Disable global variable lookup in Python (and my own answer there), I have had problems when using a function with optional parameters such as in this minimal example:
import types
def noglobal(f):
return types.FunctionType(f.__code__, {})
@noglobal
def myFunction(x=0):
pass
myFunction()
Essentially, it fails like this:
Traceback (most recent call last):
File "SetTagValue.py", line 10, in <module>
myFunction()
TypeError: myFunction() missing 1 required positional argument: 'x'
Why is x
suddenly treated as a required parameter?
回答1:
If you want to preserve the default argument values you need to pass them as well:
import types
def noglobal(f):
return types.FunctionType(f.__code__, {}, f.__name__, f.__defaults__)
@noglobal
def myFunction(x=0):
pass
myFunction()
You can pass one last closure
parameter to types.FunctionType
, which you may also want to inherit from f.__closure__
if you want to keep functions with a closure working.
回答2:
It's because you didn't properly copy the function. If you take a look at the signature of types.FunctionType
you'll see that it accepts 5 arguments:
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
You didn't pass any argdefs
, so the function has no optional arguments any more. The correct way to copy the function is
types.FunctionType(f.__code__,
{},
f.__name__,
f.__defaults__,
f.__closure__
)
However, this leads to another problem: Cutting off access to globals also cuts off access to builtins. If you try to use print
or open
or dict
or something similar in myFunction
, you'll get a NameError
. So the really correct way to write your decorator is this:
import builtins
import types
def noglobal(f):
return types.FunctionType(f.__code__,
{'__builtins__': builtins},
f.__name__,
f.__defaults__,
f.__closure__
)
来源:https://stackoverflow.com/questions/54985487/how-can-an-optional-parameter-become-required