如何需要可选参数?

问题描述 投票:2回答:2

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

python optional-parameters globals
2个回答
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__


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__
                   )

但是,这会导致另一个问题:切断对全局变量的访问也会切断对内置函数的访问。如果你试图在print使用opendictmyFunction或类似的东西,你会得到一个NameError。所以编写装饰器的正确方法是这样的:

import builtins
import types

def noglobal(f):
    return types.FunctionType(f.__code__,
                              {'__builtins__': builtins},
                              f.__name__,
                              f.__defaults__,
                              f.__closure__
                              )
© www.soinside.com 2019 - 2024. All rights reserved.