# 报错TypeError: The function construct needs 0 positional argument and 0 default argument, but provided 1

**1. 系统环境**

```
Hardware Environment(Ascend/GPU/CPU): ALL Software Environment: MindSpore version (source or binary): 1.6.0 & Earlier versions Python version (e.g., Python 3.7.5): 3.7.6 OS platform and distribution (e.g., Linux Ubuntu 16.04): Ubuntu GCC/Compiler version (if compiled from source):
```

**2. python代码样例**

```
from mindspore.nn import Cell

class Net(Cell):
    def construct(x):
        return x

net = Net()
net(2)
```

**3. 报错信息**

```
Traceback (most recent call last): File "error_map/01/param_not_match.py", line 10, in net(2) File "/usr/local/python3.7/lib/python3.7/site-packages/mindspore/nn/cell.py", line 469, in call self._check_construct_args(*args, **kwargs) File "/usr/local/python3.7/lib/python3.7/site-packages/mindspore/nn/cell.py", line 400, in _check_construct_args f"The function construct needs {positional_args} positional argument and {default_args} default " TypeError: The function construct needs 0 positional argument and 0 default argument, but provided 1
```

**4. 原因分析**

首先查看报错信息“TypeError: The function construct needs 0 positional argument and 0 default argument, but provided 1”

报错信息直译为：函数construct需要0个位置参数和0个默认参数，但提供了1个

为了理解报错信息的含义，需要解释两个名词positional argument和default argument。要解释这两个名词首先要理解什么是argument\(调用时输入的实参，有具体的值\)，说argument就必须要说Parameter\(函数定义时声明的形参，没有具体的值\)。以样例代码为列函数def construct\(x\)定义中的x是Parameter, net\(2\)中的2是argument。positional argument是需要通过输入顺序\(位置\)来识别具体输入和Parameter绑定关系的argument。 Python官方资料中并没有default argument这个概念，只有default value；含有default value的Parameter在函数调用时可以不输入对应的argument， 框架在函数调用时会使用default value作为argument。

理解位置参数和默认参数后，可以将报错信息更直白表述为：类Net的construct函数需要0个入参，但提供了1个

这样一来文字本身的含义是清晰了， 但依然存在两个疑问：

什么时候如何调用了类Net的construct函数？

类Net的construct函数原型def construct\(x\)有一个入参数x，为何报错信息胡扯需要0个入参?

疑问1的答案是：

MindSpore框架代码为类nn.Cell重写了魔法函数\_\_call\_\_，并在\_\_call\_\_中调用了construct，重写 \_\_call\_\_的效果是可以像调用函数一样调用类实例，例如样例代码中的：net\(2\)；感兴趣的同学可以自行查看框架发布包中nn.Cell.\_\_call\_\_的定义。

疑问2的答案是：

construct是通过Net的Instance methods机制调用的， construct的首个入参是由Python框架插入的类实例\(与函数声明中的第一个Parameter对应，一般叫作self， 样例中叫x\)，调用时输入的2其实是它的第2个argument。经过python框架的调用原型为 construct\(net, 2\)，它有2个arguments。

用如下Python原生代码会报类似错误：TypeError: construct\(\) takes 1 positional argument but 2 were given

```
class Net:
    def construct(x):
        print(str(x))

net = Net()
net.construct(1)
```

MindSpore的报错信息是站在直接调用Instance methods角度来报的，它并不认为Python框架插入的类实例为用户输入argument，从def construct\(x\)的声明来看，它不需要调用方提供arguments，所以样例代码中MindSpore报错:“TypeError: The function construct needs 0 positional argument and 0 default argument, but provided 1”

**5. 解决方法**

通过上一章节的分析可以看出def construct\(x\):的定义是错误的，缺少了self入参，其正确定义为：def construct\(self, x\):

**6. 平台改进点**

报错信息上尽量与原生python保持一致，方便开发者进行理解。

优化后报错信息如下：

Traceback \(most recent call last\): File "/home/zhangzhaoju/ms\_dev/error\_map/01/param\_not\_match.py", line 10, in net\(2\) File "/usr/local/python3.7/lib/python3.7/site-packages/mindspore/nn/cell.py", line 475, in call self.\_check\_construct\_args\(\*args, \*\*kwargs\) File "/usr/local/python3.7/lib/python3.7/site-packages/mindspore/nn/cell.py", line 402, in \_check\_construct\_args raise TypeError\(f"Method construct\(\) of class \{self.class.name\}, " TypeError: Method construct\(\) of class Net takes 0 positional arguments but 1 were given.

**7. 总结**

MindSpore前端语法是Python语法的子集， 撰写模型时需要遵循Python语法。学习一些python语言的书籍，对于MindSpore运行机制理解和问题定位很有帮助。

**8. 参考文档**

魔法函数原理：[https://docs.python.org/3/reference/datamodel.html\#special-method-names](https://docs.python.org/3/reference/datamodel.html#special-method-names)

实例函数原理：[https://docs.python.org/3/reference/datamodel.html\#the-standard-type-hierarchy](https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy)\(instanse method 章节\)

