python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > python类方法中的self关键字

python类方法中的self关键字使用

作者:m0_38063172

这篇文章主要介绍了python类方法中的self关键字使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

之前学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即是表示实例化对象的形参。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文