参数验证,Python中的最佳实践

Bhu*_*han 4 python

让我们举一个API的例子

def get_abs_directory(self, path):
    if os.path.isdir(path):
       return path
    else:
       return os.path.split(os.path.abspath(path))[0]
Run Code Online (Sandbox Code Playgroud)

我的问题是验证参数的pythonic方法是什么,我应该忽略任何类型的验证(我观察到所有的python代码都没有验证)

  1. 我应该检查"路径"是否为空而不是空
  2. 我应该始终检查路径的"类型"
  3. 一般来说,我应该检查参数的类型?(我猜不是动态类型的python)

此问题并非特定于文件IO,而是仅将FileIO用作示例

Rod*_*ins 7

EAFP是 Python 中针对此类情况的事实上的标准,同时,如果您愿意,没有什么可以阻止您一直遵循LBYL 。

然而,当EAFP适用时,有一些保留:

  • 当代码仍然能够处理异常情况、在某个时刻中断或使调用者能够验证可能的错误时,最好只遵循 EAFP原则

  • 当使用EAFP导致无提示错误时,显式检查/验证 ( LBYL ) 可能是最好的。

关于这一点,有一个Python模块,parameters-validation,可以在您需要时简化函数参数的验证:

@validate_parameters
def register(
    token: strongly_typed(AuthToken),
    name: non_blank(str),
    age: non_negative(int),
    nickname: no_whitespaces(non_empty(str)),
    bio: str,
):
    # do register
Run Code Online (Sandbox Code Playgroud)

免责声明:我是项目维护者。


Gam*_*iac 6

正如此处的文档所述,Python遵循EAFP方法.这意味着我们通常使用更多trycatch块而不是尝试验证参数.让我来证明:

import os


def get_abs_directory(path):
    try:
        if os.path.isdir(path):
            return path
        else:
            return os.path.split(os.path.abspath(path))[0]
    except TypeError:
        print "You inserted the wrong type!"


if __name__ == '__main__':
    get_abs_directory(1)  # Using an int instead of a string, which is caught by TypeError
Run Code Online (Sandbox Code Playgroud)

但是,您可以希望在LBYL(Look Before You Leap)样式中编码,这看起来像这样:

import os


def get_abs_directory(path):

    if not isinstance(path, str):
        print "You gave us the wrong type, you big meany!"
        return None

    if os.path.isdir(path):
        return path
    else:
        return os.path.split(os.path.abspath(path))[0]

if __name__ == '__main__':
    get_abs_directory(1)
Run Code Online (Sandbox Code Playgroud)

  • @Bhushan不,只是让它*尝试*进行计算.如果某些内容失败,异常将自动冒泡到调用方.除非是实际的用户输入,否则假设人们正确使用您的API. (2认同)
  • @Bhushan我想我在谈到EAFP时回答了你的问题.这意味着你必须_try_一些东西,如果它失败了,你就处理它.这是使用Python编程时的操作方式.因为,如果你考虑一下,你通常不会得到错误的输入,所以试图在每次调用时检查它是浪费资源. (2认同)