Pythonのselfの意味を明らかにする

3858 ワード

Pythonのクラスの書き方を習い始めたばかりの頃は面倒でしたが、なぜ定義するときに必要とし、呼び出すときに必要としないのか、なぜ内部を簡略化してキーボードを叩く回数を減らすことができないのか.selfはクラスのインスタンスを表し、クラスではありません.
class Test():
    def test_1(self):
        print(self)
        print(self.__class__)
 
t = Test()
t.test_1()
# <__main__.test object="" at="">
# 

上記の例から明らかなようにselfはクラスのインスタンスを表す.そしてself.classはクラスを指します.
selfはselfと書く必要はありません
class Test:
    def test_1(this):
        print(this)
        print(this.__class__)
 
t = Test()
t.test_1()

これに変更すると、実行結果はまったく同じです.
もちろん、約束の習慣を尊重してselfを使ったほうがいいです.
selfは書かなくてもいいですか?
Pythonの解釈器の内部でt.test_を呼び出すと1()の場合、実際にPythonはTestと解釈する.test_1(t)、すなわちselfをクラスのインスタンスに置き換える.
上のt.test_を1()1行を書き換えてみると,実行後の実際の結果は全く同じである.
実際にselfは定義時に省略できないことを一部説明していますが、どうしても試してみるなら、以下を見てください.
class Test:
    def test_1():
        print(self)
 
t = Test()
t.test_1()

実行時のアラートエラーは次のとおりです:test_1定義時にパラメータはありませんが、実行時にパラメータを強制的に渡しました.
t.test_を説明したので1()はTestに等しい.test_1(t)なので、プログラムはパラメータtを1つ多く伝えるように注意します.
Traceback (most recent call last):
  File "h.py", line 6, in 
    t.prt()
TypeError: prt() takes 0 positional arguments but 1 was given

もちろん、定義および呼び出し時にクラスインスタンスを送信しない場合は、クラスメソッドです.
class Test:
    def test_1():
        print(__class__)
Test.test_1()

実行結果は次のとおりです.
# 

継承時に受信されるインスタンスは、selfを定義したクラスのインスタンスではなく、その受信されたインスタンスです.
class Parent():
    def test_1(self):
        print(self)
 
class Child(Parent):
    def test_2(self):
        print(self)
c = Child()
c.test_2()
c.test_1()
p = Parent()
p.test_1()

実行結果は次のとおりです.
<__main__.child object="" at="">
<__main__.child object="" at="">
<__main__.parent object="" at="">

説明:
c.cprt()を実行しても問題は理解できないはずです.Childクラスのインスタンスを指します.
でもc.test_を実行しています1()の場合、Childに等しい.test_1©,したがってselfは依然としてChildクラスのインスタンスを指し、selfにはtest_が定義されていないため1()メソッドなので、継承ツリーに沿って上を探すと、親パラメータでtest_が定義されていることがわかります.1()メソッドなので、正常に呼び出されます.
記述子クラスではselfは記述子クラスのインスタンスを指す
class Desc():
    def __get__(self, ins, cls):
        print('self in Desc: %s ' % self )
        print(self, ins, cls)
class Test():
    x = Desc()
    def test_1(self):
        print('self in Test: %s' % self)
t = Test()
t.test_1()
t.x

実行結果は次のとおりです.
self in Test: <__main__.test object="" at="">
self in Desc: <__main__.desc object="" at="">
<__main__.desc object="" at=""> <__main__.test object="" at=""> 

なぜDescクラスで定義されたselfはそのインスタンスtを呼び出すべきではないのですか?どうしてDescクラスのインスタンスになったのでしょうか.
注意:ここでは、t.x、すなわちTestクラスのインスタンスtの属性xを呼び出す必要があります.インスタンスtには属性xが定義されていないため、クラス属性xが見つかりました.この属性は記述子属性であり、Descクラスのインスタンスであるため、ここではTestを使用する方法はありません.
では,クラスを直接介して属性xを呼び出すと同様の結果が得られる.
次はt.xをTestに変更します.x実行の結果.
self in Test: <__main__.test object="" at="">
self in Desc: <__main__.desc object="" at="">
<__main__.desc object="" at=""> None 

ディスクリプタクラスでは、ディスクリプタを呼び出すインスタンスが誰であるかを知る必要がある場合が多いため、ディスクリプタクラスには、呼び出すクラスインスタンスを表す2番目のパラメータinsが存在するため、t.xでは、3行目の実行結果の2番目の項目が表示される.Testを採用しましたxが呼び出されると、インスタンスがないためNoneに戻ります.
まとめ
self        ,           。
self          ,            self
self           。