python类方法中的self关键字使用
作者:m0_38063172
之前学python爬虫的时候要把函数封装到类里面,写成类方法,知道在python的类方法中第一个参数应该是self,但对self代表的具体意义不甚了了。
最近在看Java,对面向对象编程的了解更多了一点,终于彻底弄明白self到底是什么了。
Python的类
在python中,所有的类都直接或间接继承自Object类,定义了类之后就定义了一个命名空间,里面定义的属性可以通过类名来引用。
新定义的类中有一些Object中有的属性,可以在其中定义其他变量或者函数。实例化之后会创建一个对象,该对象脱胎于类,并且其中的属性动态地和类中的属性产生关联:
class A: pass a = A()
这段代码创建了一个类A,并且对它进行了实例化,实例化之后的对象绑定为变量a。
我可以看看A里面和a里面分别有什么:
In [38]: dir(A) Out[38]: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
In [39]: dir(a) Out[39]: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
用dir函数输出A中和a中的属性后,我们可以看到A和a中的属性是一样的。
我们可以向其中添加属性,添加属性时必须初始化:
In [40]: A.b --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-40-ebcfc7dbf31a> in <module>() ----> 1 A.b AttributeError: type object 'A' has no attribute 'b'
In [41]: A.b = 1
现在我们可以看看A和a中的属性发生了什么变化:
In [42]: dir(A) Out[42]: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'b']
In [43]: dir(a) Out[43]: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'b']
In [74]: A.b Out[74]: 1 In [75]: a.b Out[75]: 1
我们可以看到,在A中和它的实例化对象中现在都有了属性b,而且它们的值相等。
如果我们给A的实例化对象中添加属性呢:
In [44]: a.c = 2 In [45]: hasattr(a, c) --------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-45-15d927c71e90> in <module>() ----> 1 hasattr(a, c) NameError: name 'c' is not defined
竟然报错了,c没有定义,报错的原因是A的实例化对象a的命名空间中有c,但是公共命名空间中没有c,所以我们再试一次:
In [58]: c = a.c In [59]: hasattr(a, 'c') Out[59]: True In [60]: hasattr(A, 'c') Out[60]: False
我们可以看到,a中有c,但是A中并没有c。是不是因为c指向的是a.c所以A中没有呢:
In [61]: b = a.b In [62]: hasattr(A, 'b') Out[62]: True
确实是因为在类的实例化对象中添加的属性不会加入类中。
我们接着看给A或a中加入函数属性会发生什么:
In [78]: A.foo = lambda x : x + 1 In [79]: A.foo(1) Out[79]: 2 In [80]: a.foo(1) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-80-7dc85fd7a693> in <module>() ----> 1 a.foo(1) TypeError: <lambda>() takes 1 positional argument but 2 were given
python方法函数中的self关键字
上面执行"a.foo(1)"语句时有个报错,说只需要一个参数,但是给了两个参数,这第二个参数是怎么来的,为什么A.foo(1)就不会出错。
这里我们可以引出python类中的方法函数,方法函数指的是通过类的实例化对象调用的函数,方法函数的第一个形参表示类的实例化对象,通常写成self。
执行a.foo(1)时就相当于执行A.foo(a,1),因为A.foo()中只有一个形参,传入的参数多于需要的参数,所以发生类型错误。
我们在A的定义中重新定义foo:
class A: def foo(self, n): print(n+1) a = A()
现在我们在a中调用foo就不会有问题了:
In [85]: a.foo(1) 2
我们也可以试试调用A.foo:
In [86]: A.foo(a, 1) 2
总结
python的类中定义函数时的self关键字跟python的方法函数有关,方法函数由类的实例化对象调用,需要把调用它的实例化对象传入方法函数中,self即是表示实例化对象的形参。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。