问题
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