Python 检查函数参数的最佳方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19684434/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 14:22:03  来源:igfitidea点击:

Best way to check function arguments?

pythonfunctionarguments

提问by carmellose

I'm looking for an efficient way to check variables of a Python function. For example, I'd like to check arguments type and value. Is there a module for this? Or should I use something like decorators, or any specific idiom?

我正在寻找一种有效的方法来检查 Python 函数的变量。例如,我想检查参数类型和值。有这个模块吗?或者我应该使用装饰器之类的东西,还是任何特定的习惯用法?

def my_function(a, b, c):
    """An example function I'd like to check the arguments of."""
    # check that a is an int
    # check that 0 < b < 10
    # check that c is not an empty string

采纳答案by bruno desthuilliers

The most Pythonic idiom is to clearly documentwhat the function expects and then just try to use whatever gets passed to your function and either let exceptions propagate or just catch attribute errors and raise a TypeErrorinstead. Type-checking should be avoided as much as possible as it goes against duck-typing. Value testing can be OK – depending on the context.

最 Pythonic 的习惯用法是清楚地记录函数的期望值,然后尝试使用传递给函数的任何内容,要么让异常传播,要么只捕获属性错误并引发 a TypeError。应该尽可能避免类型检查,因为它与鸭子类型背道而驰。价值测试可能没问题——取决于上下文。

The only place where validation really makes sense is at system or subsystem entry point, such as web forms, command line arguments, etc. Everywhere else, as long as your functions are properly documented, it's the caller's responsibility to pass appropriate arguments.

验证真正有意义的唯一地方是系统或子系统入口点,例如 Web 表单、命令行参数等。在其他任何地方,只要您的函数被正确记录,调用者就有责任传递适当的参数。

回答by Matthew Plourde

One way is to use assert:

一种方法是使用assert

def myFunction(a,b,c):
    "This is an example function I'd like to check arguments of"
    assert isinstance(a, int), 'a should be an int'
    # or if you want to allow whole number floats: assert int(a) == a
    assert b > 0 and b < 10, 'b should be betwen 0 and 10'
    assert isinstance(c, str) and c, 'c should be a non-empty string'

回答by Jo So

If you want to check **kwargs, *argsas well as normal arguments in one go, you can use the locals()function as the first statement in your function definition to get a dictionary of the arguments.

如果您想一次性检查**kwargs*args以及普通参数,您可以使用该locals()函数作为函数定义中的第一条语句来获取参数字典。

Then use type()to examine the arguments, for example whilst iterating over the dict.

然后用于type()检查参数,例如在迭代字典时。

def myfunc(my, args, to, this, function, **kwargs):
    d = locals()
    assert(type(d.get('x')) == str)
    for x in d:
        if x != 'x':
            assert(type(d[x]) == x
    for x in ['a','b','c']:
        assert(x in d)

    whatever more...

回答by Mats Kindahl

Normally, you do something like this:

通常,您会执行以下操作:

def myFunction(a,b,c):
   if not isinstance(a, int):
      raise TypeError("Expected int, got %s" % (type(a),))
   if b <= 0 or b >= 10:
      raise ValueError("Value %d out of range" % (b,))
   if not c:
      raise ValueError("String was empty")

   # Rest of function

回答by FallenAngel

def someFunc(a, b, c):
    params = locals()
    for _item in params:
        print type(params[_item]), _item, params[_item]

Demo:

演示:

>> someFunc(1, 'asd', 1.0)
>> <type 'int'> a 1
>> <type 'float'> c 1.0
>> <type 'str'> b asd

more about locals()

更多关于当地人()

回答by Nicolas Brugneaux

def myFunction(a,b,c):
"This is an example function I'd like to check arguments of"
    if type( a ) == int:
       #dostuff
    if 0 < b < 10:
       #dostuff
    if type( C ) == str and c != "":
       #dostuff

回答by Paulo Bu

If you want to do the validation for several functions you can add the logic inside a decorator like this:

如果要对多个函数进行验证,可以在装饰器中添加逻辑,如下所示:

def deco(func):
     def wrapper(a,b,c):
         if not isinstance(a, int)\
            or not isinstance(b, int)\
            or not isinstance(c, str):
             raise TypeError
         if not 0 < b < 10:
             raise ValueError
         if c == '':
             raise ValueError
         return func(a,b,c)
     return wrapper

and use it:

并使用它:

@deco
def foo(a,b,c):
    print 'ok!'

Hope this helps!

希望这可以帮助!

回答by rlms

Edit: as of 2019 there is more support for using type annotations and static checking in Python; check out the typingmodule and mypy. The 2013 answer follows:

编辑:截至 2019 年,更多支持在 Python 中使用类型注释和静态检查;检查打字模块和mypy。2013年的回答如下:



Type checking is generally not Pythonic. In Python, it is more usual to use duck typing. Example:

类型检查通常不是 Pythonic。在 Python 中,更常用的是鸭子输入。例子:

In you code, assume that the argument (in your example a) walks like an intand quacks like an int. For instance:

在您的代码中,假设参数(在您的示例中a)像 anint一样行走,像 an一样嘎嘎叫int。例如:

def my_function(a):
    return a + 7

This means that not only does your function work with integers, it also works with floats and any user defined class with the __add__method defined, so less (sometimes nothing) has to be done if you, or someone else, want to extend your function to work with something else. However, in some cases you might need an int, so then you could do something like this:

这意味着您的函数不仅可以处理整数,还可以处理浮点数和任何定义了__add__方法的用户定义类,因此如果您或其他人想要将您的函数扩展到和别的东西一起工作。但是,在某些情况下,您可能需要一个int,因此您可以执行以下操作:

def my_function(a):
    b = int(a) + 7
    c = (5, 6, 3, 123541)[b]
    return c

and the function still works for any athat defines the __int__method.

并且该函数仍然适用于任何a定义该__int__方法的人。

In answer to your other questions, I think it is best (as other answers have said to either do this:

在回答您的其他问题时,我认为这是最好的(正如其他答案所说的那样:

def my_function(a, b, c):
    assert 0 < b < 10
    assert c        # A non-empty string has the Boolean value True

or

或者

def my_function(a, b, c):
    if 0 < b < 10:
        # Do stuff with b
    else:
        raise ValueError
    if c:
        # Do stuff with c
    else:
        raise ValueError

Some type checking decorators I made:

我制作的一些类型检查装饰器:

import inspect

def checkargs(function):
    def _f(*arguments):
        for index, argument in enumerate(inspect.getfullargspec(function)[0]):
            if not isinstance(arguments[index], function.__annotations__[argument]):
                raise TypeError("{} is not of type {}".format(arguments[index], function.__annotations__[argument]))
        return function(*arguments)
    _f.__doc__ = function.__doc__
    return _f

def coerceargs(function):
    def _f(*arguments):
        new_arguments = []
        for index, argument in enumerate(inspect.getfullargspec(function)[0]):
            new_arguments.append(function.__annotations__[argument](arguments[index]))
        return function(*new_arguments)
    _f.__doc__ = function.__doc__
    return _f

if __name__ == "__main__":
    @checkargs
    def f(x: int, y: int):
        """
        A doc string!
        """
        return x, y

    @coerceargs
    def g(a: int, b: int):
        """
        Another doc string!
        """
        return a + b

    print(f(1, 2))
    try:
        print(f(3, 4.0))
    except TypeError as e:
        print(e)

    print(g(1, 2))
    print(g(3, 4.0))

回答by Games Brainiac

There are different ways to check what a variable is in Python. So, to list a few:

有多种方法可以检查 Python 中的变量。所以,列出一些:

  • isinstance(obj, type)function takes your variable, objand gives you Trueis it is the same type of the typeyou listed.

  • issubclass(obj, class)function that takes in a variable obj, and gives you Trueif objis a subclass of class. So for example issubclass(Rabbit, Animal)would give you a Truevalue

  • hasattris another example, demonstrated by this function, super_len:

  • isinstance(obj, type)函数接受您的变量,obj并告诉您True它是否与type您列出的类型相同。

  • issubclass(obj, class)函数接受一个变量obj,并给出Trueifobj是 的子类class。所以例如issubclass(Rabbit, Animal)会给你一个True价值

  • hasattr是另一个例子,由这个函数演示,super_len



def super_len(o):
    if hasattr(o, '__len__'):
        return len(o)

    if hasattr(o, 'len'):
        return o.len

    if hasattr(o, 'fileno'):
        try:
            fileno = o.fileno()
        except io.UnsupportedOperation:
            pass
        else:
            return os.fstat(fileno).st_size

    if hasattr(o, 'getvalue'):
        # e.g. BytesIO, cStringIO.StringI
        return len(o.getvalue())


hasattrleans more towards duck-typing, and something that is usually more pythonicbut that term is up opinionated.

hasattr更倾向于duck-typing,并且通常更像pythonic,但该术语是自以为是。

Just as a note, assertstatements are usually used in testing, otherwise, just use if/elsestatements.

请注意,assert语句通常用于测试,否则,只需使用if/else语句。

回答by DominikStyp

You can use Type Enforcement accept/returns decorators from PythonDecoratorLibraryIt's very easy and readable:

您可以使用PythonDecoratorLibrary 中的Type Enforcement 接受/返回装饰器, 它非常简单易读:

@accepts(int, int, float)
def myfunc(i1, i2, i3):
    pass