How can an optional parameter become required?

时光总嘲笑我的痴心妄想 提交于 2019-12-11 02:41:44

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!