如何需要一个可选参数?

时间:2019-03-04 14:39:28

标签: python optional-parameters globals

基于Disable global variable lookup in Python(和我自己的回答),使用带有可选参数的函数时遇到了问题,例如以下最小示例:

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突然被视为必需参数?

2 个答案:

答案 0 :(得分:3)

这是因为您没有正确复制该功能。如果看一下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__
                   )

但是,这导致了另一个问题:切断对全局变量的访问也切断了对内置函数的访问。如果您尝试使用printopendictmyFunction中的类似内容,则会得到NameError。因此,真正编写装饰器的正确方法是:

import builtins
import types

def noglobal(f):
    return types.FunctionType(f.__code__,
                              {'__builtins__': builtins},
                              f.__name__,
                              f.__defaults__,
                              f.__closure__
                              )

答案 1 :(得分:2)

如果要保留默认参数值,还需要传递它们:

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__继承它。