如何在调用__init__之前检查参数类型

问题描述

我需要检查__init__()中的参数类型。我是这样做的:

class Matrix:

    def __init__(self,matrix):
        """
        if type(matrix) != list raise argument error
        """
        if type(matrix) != list:
            raise TypeError(f"Expected list got {type(matrix)}")
        self.matrix = matrix


a = 5
new_matrix = Matrix(a)

但是当TypeError上升时,__init__()方法已经被调用。我想知道如何在调用它之前执行此操作。我认为可以使用metaclass在某些时候“拦截”并引发错误,但我不知道怎么做。

解决方法

首先: 通常,除非绝对必要,否则通常不要在Python中进行此类运行时检查。这个想法是,在这种情况下,传递给__init__的所有内容的行为都将与列表类似,足以代替其使用。那就是“鸭子打字”的想法。

第二: 如果确实需要进行此检查,那么就像您所做的那样,在函数或方法主体中使用if语句。没关系“方法已运行,并且在其中引发了错误”,这是动态类型在Python中的工作方式。

第三: 实际上,有一种方法可以防止程序以错误的参数类型调用__init__,那就是使用静态类型检查。当您运行检查器时,您的程序将在准备步骤中出错,例如“ mypy”,这几乎是在同一时间某些静态语言会引发错误:在运行之前在显式步骤中对它们进行编译。静态类型检查可以增加您认为需要的安全性-但是用Python编写代码是一个全新的样板和官僚机构。在网络上搜索“ python静态类型检查”可以列出一些要点,您便可以开始学习这一点-我看到的第二个链接相当有趣:https://realpython.com/python-type-checking/

第四: 如果您选择基于if的检查,则应检查所获取的对象是否出于您的目的而“足够列表”,而不是“ type(a)!= list”。这将禁止列表的子类。 not isinstance(a,list)将接受列表子类,但会阻止其他几种可能有效的对象类型。根据您的需要,您的代码可以与任何“序列”类型一起使用。在这种情况下,您可以导入collections.abc.Sequence并检查您的参数是否是该参数的实例-这将允许您的方法的用户使用任何具有长度的类,并且可以按顺序检索itens。

而且,只需重复一遍:在方法内部进行此检查绝对没有问题。通过创建一个可以进行类型检查的复杂装饰器,可以将其排除在外-实际上,有些Python包可以使用类型注释,就像静态类型检查工具所使用的那样,并且可以进行运行时检查。但这不会为您节省执行时间。静态类型检查会在运行之前完成,但是尽管如此,获取的资源还是可以忽略的。

最后,不,这与元类无关。可以使用元类将装饰器添加到所有方法中,并让这些装饰器执行运行时检查-但您仍然可以仍然明确地使用装饰器。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...