Pythonにおけるselfの使い方の詳細

15292 ワード

Pythonのselfの使い方を紹介する前に、まずPythonのクラスとインスタンスを紹介します......オブジェクト向けの最も重要な概念はクラス(class)とインスタンス(instance)で、クラスは抽象的なテンプレートで、例えば学生という抽象的なもので、1つのStudentクラスで表すことができます.インスタンスは、クラスに基づいて作成された特定のオブジェクトであり、各オブジェクトはクラスから同じメソッドを継承しますが、それぞれのデータが異なる場合があります.1、Studentクラスを例にとると、Pythonでは、定義クラスは以下の通りである.
class Student(object):
    pass

(Object)はそのクラスがどのクラスから継承されたかを表し、Objectクラスはすべてのクラスが継承するクラスである.
2、インスタンス:クラスを定義したら、StudioクラスからStudioのインスタンスを作成できます.インスタンスの作成はクラス名+()で行います.
student = Student()

3、クラスはテンプレートとして機能するため、インスタンスを作成するときに、バインドしなければならないと思う属性を強制的に記入することができます.ここではPythonの1つの内蔵メソッド__init__メソッドを用い,例えばStudentクラスでname,scoreなどの属性を縛る.
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

ここで、(1)、__init__メソッドの第1のパラメータは、常にselfであり、作成されたクラスインスタンス自体を表すため、__init__メソッドの内部では、selfが作成されたインスタンス自体を指すため、selfに様々な属性をバインドすることができる.(2)、__init__メソッドがあれば、インスタンスを作成するときに空のパラメータを入力することはできません.__init__メソッドに一致するパラメータを入力する必要がありますが、selfは送信する必要はありません.Python解釈器は自分でインスタンス変数を入力します.
>>>student = Student("Hugh", 99)
>>>student.name
"Hugh"
>>>student.score
99

なお、ここではselfはクラス自体を指し、self.nameStudentクラスの属性変数であり、Studentクラスの所有である.nameは外部から伝達されたパラメータであり、Student類が持参したものではない.したがって、self.name = nameとは、外部から伝達されたパラメータnameの値をStudentクラス独自の属性変数self.nameに付与することを意味する.
4、通常の数と比較して、クラスで定義された関数は少しだけ異なります.つまり、第1のパラメータは常にクラスのインスタンス変数selfであり、呼び出し時にパラメータを渡す必要はありません.それ以外に、クラスの方法(関数)は普通の関数と何の違いもなくて、あなたはデフォルトのパラメータ、可変パラメータあるいはキーワードパラメータ(*argsは可変パラメータで、argsは1つのtupleを受信して、**kwはキーワードパラメータで、kwは1つのdictを受信します).
5、Studentクラスインスタンス自体がこれらのデータを持っている以上、これらのデータにアクセスするには、外部の関数からアクセスする必要はなく、Studentクラスの内部で直接データにアクセスする関数(メソッド)を定義することで、「データ」をカプセル化することができます.これらのカプセル化されたデータの関数は、Studentクラス自体に関連付けられており、クラスと呼ばれるメソッドです.
class Student(obiect):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def print_score(self):
        print "%s: %s" % (self.name, self.score)
>>>student = Student("Hugh", 99)
>>>student.print_score
Hugh: 99

これにより、Studentクラスを外部から見ると、インスタンスを作成するにはnameとscoreが必要であることを知る必要があります.どのように印刷するかは、Studioクラスの内部で定義されており、これらのデータと論理はカプセル化されており、呼び出しは簡単ですが、内部実装の詳細は分かりません.
内部属性が外部からアクセスされないようにするには、属性の名前の前に下線を2つ付けることができます.Pythonでは、インスタンスの変数名が先頭になると、プライベート変数(private)になり、内部のみアクセスでき、外部はアクセスできないので、Studioクラスを変更します.
class Student(object):

    def __init__(self, name, score):
        self.__name = name
        self.__score = score
    def print_score(self):
        print "%s: %s" %(self.__name,self.__score)

変更後、外部コードについては変更はありませんが、外部からインスタンス変数.__nameとインスタンス変数.__scoreにアクセスすることはできません.
>>> student = Student('Hugh', 99)
>>> student.__name
Traceback (most recent call last):
  File "", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'

これにより、外部コードがオブジェクトの内部の状態を勝手に変更できないことが確保され、アクセス制限の保護によってコードがより丈夫になります.
しかし、外部コードがnameとscoreを取得する場合はどうしますか?Studentクラスにget_を追加できますnameとget_scoreのような方法:
class Student(object):
    ...

    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score

外部コードのscoreの変更を許可する場合はどうしますか?Studioクラスにset_を追加できますscoreメソッド:
class Student(object):
    ...

    def set_score(self, score):
        self.__score = score

なお、Pythonでは、変数名は__xxx__に類似しており、すなわち二重下線で始まり、二重下線で終わるのは特殊変数であり、特殊変数はprivate変数ではなく直接アクセス可能であるため、__name____score__のような変数名は使用できない.
下線で始まるインスタンス変数の名前が表示される場合があります.たとえば、_name,このようなインスタンス変数は外部からアクセス可能であるが,一般的な規定に従って,このような変数を見ると,「私はアクセスできるが,私をプライベート変数と見なして,勝手にアクセスしないでください」という意味である.
パッケージのもう1つの利点は、Studioクラスにいつでも新しい方法を追加できることです.たとえば、get_grade:
class Student(object):
    ...
    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'

同様に、get_gradeメソッドは、内部実装の詳細を知る必要がなく、インスタンス変数上で直接呼び出すことができる.
>>> student.get_grade()
'A'

6、selfの注意深い使い方(1)、selfはクラスの例を表し、クラスではない.
class Test:
    def ppr(self):
        print(self)
        print(self.__class__)

t = Test()
t.ppr()
    :
<__main__.test object="" at="" class="hljs-number">0x000000000284E080>
<class '__main__.Test'>

上記の例から明らかなようにselfはクラスのインスタンスを表す.self.__class__はクラスを指します.注意:selfをthisに置き換えると、結果も同じですが、Pythonでは約束通りのselfを使うのが望ましいです.(2)、selfは書かなくてもいいですか?Python解釈器の内部でt.ppr()を呼び出すと、実際にPythonはTestと解釈する.ppr(t)、すなわちselfをクラスのインスタンスに置き換えた.
class Test:
    def ppr():
        print(self)

t = Test()
t.ppr()

実行結果は次のとおりです.
Traceback (most recent call last):
  File "cl.py", line 6, in <module> t.ppr() TypeError: ppr() takes 0 positional arguments but 1 was given

実行時アラートエラーは次のとおりです.pprは定義時にパラメータがありませんが、実行時にパラメータを強制的に送信しました.
t.ppr()はTestに等しいと説明したからである.ppr(t)なので、プログラムはパラメータtを1つ多く伝えるように注意します.
ここでは、selfが定義時に省略してはならないことを一部説明している.
もちろん、定義および呼び出し時にクラスインスタンスを送信しない場合は、クラスメソッドです.
class Test:
    def ppr():
        print(__class__)

Test.ppr()

    :
<class '__main__.Test'>

(3)、継承時にどのインスタンスが渡されるか、selfを定義したクラスのインスタンスではなく、そのインスタンスが渡される.
class Parent:
    def pprt(self):
        print(self)

class Child(Parent):
    def cprt(self):
        print(self)
c = Child()
c.cprt()
c.pprt()
p = Parent()
p.pprt()

実行結果:
<__main__.child class="hljs-class">object at 0x0000000002A47080>
<__main__.child class="hljs-class">object at 0x0000000002A47080>
<__main__.parent class="hljs-class">object at 0x0000000002A47240>

説明:c.cprt()を実行するときに問題を理解していないはずです.Childクラスのインスタンスを指します.ただしc.pprt()を実行する場合はChildと同等である.pprt(c)であるためselfは依然としてChildクラスのインスタンスを指し,selfにはpprt()メソッドが定義されていないため,継承ツリーに沿って上を探すと親クラスParentにpprt()メソッドが定義されていることが判明し,呼び出すことに成功する.
(4)、記述子クラスにおいてselfは記述子クラスの例を指す
class Desc:
    def __get__(self, ins, cls):
        print('self in Desc: %s ' % self )
        print(self, ins, cls)
class Test:
    x = Desc()
    def prt(self):
        print('self in Test: %s' % self)
t = Test()
t.prt()
t.x

実行結果は次のとおりです.
self in Test: <__main__.test object="" at="" class="hljs-number">0x0000000002A570B8>
self in Desc: <__main__. class="hljs-keyword">Desc object at 0x000000000283E208>
<__main__. class="hljs-keyword">Desc object at 0x000000000283E208> <__main__.test object="" at="" class="hljs-number">0x0000000002A570B8> <class '__main__.Test'>

ここで主な疑問は、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="" class="hljs-number">0x00000000022570B8>
self in Desc: <__main__. class="hljs-keyword">Desc object at 0x000000000223E208>
<__main__. class="hljs-keyword">Desc object at 0x000000000223E208> None <class '__main__.Test'>

まとめ:以上は前にPythonを勉强した时のまとめですが、今はブログで提示しています.pysparkでselfを呼び出して出会った问题を敷き詰めています.后でjavaと比べて、未完です.