pythonクラスメソッドのselfキーワード

33134 ワード

以前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__']

Aとaの属性をdir関数で出力すると,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)」文を実行するとき、1つのパラメータしか必要ないというエラーがありましたが、2つのパラメータが与えられました.この2番目のパラメータはどのように来たのか、なぜA.foo(1)はエラーしませんか.ここでpythonクラスのメソッド関数を引き出すことができ、メソッド関数はクラスのインスタンス化オブジェクトによって呼び出される関数を指し、メソッド関数の最初のパラメータはクラスのインスタンス化オブジェクトを表し、通常selfと書かれる.a.foo(1)を実行する場合は、A.foo(a,1)を実行することに相当します.A.foo()には1つのパラメータしかなく、必要なパラメータよりも多くのパラメータが入力されるため、タイプエラーが発生します.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はインスタンス化オブジェクトを表すパラメータです.