0. 前言
按照国际惯例,首先声明:本文只是我自己学习的理解,虽然参考了他人的宝贵见解,但是内容不乏不准确的地方,希望批评指正,共同进步。
对于Python新手(甚至部分老手)而言,在面向对象编程类(class)中,都有一个比较困扰的参数——self。
因此写作本文加强自己的理解,也帮助别人理解。
1. 从一个问题入手理解"self"
下面是一段关于class的python代码,在这段代码中完全没有"self"这个参数,请思考下这段代码中的4个"print"哪个是可以运行的,哪个会报错?
答案后面揭晓。
class test(): def __init__(x): x.ten = 10 def multi_ten(y, z): return z*y.ten def divide_ten(w, v): return v/w.ten def hello(k): return 'hello' def world(): return 'world' TEST = test() print(TEST.multi_ten(9)) print(TEST.divide_ten(100)) print(TEST.hello()) print(TEST.world())
2. "self"的定义
Python规定在类(class)的方法(method)中,都必须有一个形参(parameter),而且必须是第一个形参,用于传递类的实例(instance)
。而这个形参,一般约定熟成取名为"self"。
类中的函数称为方法,例如上面的multi_ten()、divide_ten()这些都是方法。在Pycharm中,在类中编写方法的时候也会自动跳出“self”这个参数。
拿上面的例子来说,在multi_ten()这个方法中,第一个形参(parameter)是"y",在test()类实例化后,它传递的实参(argument)是"TEST"实例(instance),所以这里的"y"就相当于"self"。
因为"TEST"这个实参已经传入multi_ten()这个方法中,所以"TEST"实例可以调用multi_ten(),即TEST.multi_ten()。
3. __init__()
方法
__init__()
本质上是一个方法,所以其实和"self"(形参)关系不大,为什么经常把这两者联系到一起呢?
因为__init__()
是一个特殊的方法,每次创建类的新实例时__init__()
都会自动运行,这样就可以在__init__()
方法中定义以"self"为前缀的变量,例如上面的x.ten,供类中的所有方法使用。
4. 问题解析
回到最开始的问题,通过对"self"的理解,可以知道前3个print是可以运行的,最后一个会报错。
C:\Users\Lenovo\Desktop\DL\Pytest\Scripts\python.exe C:/Users/Lenovo/Desktop/DL/Pytest/test_main.py 90 10.0 hello Traceback (most recent call last): File "C:\Users\Lenovo\Desktop\DL\Pytest\test_main.py", line 22, in <module> print(TEST.world()) TypeError: world() takes 0 positional arguments but 1 was given Process finished with exit code 1
而其报错的原因“TypeError: world() takes 0 positional arguments but 1 was given”就是再说:在定义world()这个方法的时候,没有填位置形参(positional parameter),调用的时候应该也是给0个位置实参(positional argument),但是实际使用却给了一个位置实参(positional argument)——“TEST”,所以会报错。
5. 结语
最后再说明一下,虽然Python的类在"self"的上可以用其他变量替代,但是这种操作都是极其不推荐的,无论新手老手,在任何情况下,在"self"的位置上都应该老老实实地写成"self"。上面那段代码应该这样写:
class test(): def __init__(self): self.ten = 10 def multi_ten(self, z): return z*self.ten def divide_ten(self, v): return v/self.ten def hello(self): return 'hello' def world(self): return 'world' TEST = test() print(TEST.multi_ten(9)) print(TEST.divide_ten(100)) print(TEST.hello()) print(TEST.world())