Python での self の使用法を紹介する前に、まず Python のクラスとインスタンスについて紹介しましょう
オブジェクト指向の最も重要な概念はクラスとインスタンスであることはわかっています。クラスは抽象テンプレートです。たとえば、抽象学生のようなものは Student クラスで表すことができます。インスタンスはクラスに基づいて作成された特定の「オブジェクト」であり、各オブジェクトはクラスから同じメソッドを継承しますが、そのデータは異なる場合があります。
1. Student クラスを例に挙げます。Python では、クラスは次のように定義されます:
class Student(object): pass
(Object) は、クラスがどのクラスから継承しているかを示します。Object クラスは、すべてのクラスが継承するクラスです。継承することになります。
2. インスタンス: クラスが定義された後、Student クラスを通じて Student のインスタンスを作成できます。インスタンスはクラス名 ():
student = Student()
3 を通じて作成されます。クラスはテンプレートとして機能するため、インスタンスを作成するときに、バインドする必要があると思われる属性を強制的に埋めることができます。ここでは Python の組み込みメソッドである __init__
メソッドが使用されています。たとえば、Student クラスでは、名前やスコアなどの属性をそれに結び付けます:
class Student(object): def __init__(self, name, score): self.name = name self.score = score
ここに注意してください: (1), __init__
メソッドの最初のパラメータは常に self
であり、作成されたクラス インスタンス自体 を表します。 ## メソッドでは、それぞれを配置できます。self は作成されたインスタンス自体を指すため、このプロパティは self にバインドされます。 (2). __init__
メソッドでは、インスタンスを作成するときに空のパラメーターを渡すことはできません。__init__
メソッドに一致するパラメーターを渡す必要がありますが、self は必須ではありません。 Python インタープリターはインスタンス変数をそれ自体で渡します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">>>>student = Student("Hugh", 99)
>>>student.name
"Hugh"
>>>student.score
99</pre><div class="contentsignin">ログイン後にコピー</div></div>
さらに、ここで
はクラス自体を指します。self.name
は ## です。 #Student クラスの属性変数は、
Student クラスによって所有されます。
name は外部パラメータであり、
Student クラスに付属するパラメータではありません。したがって、
self.name = name は、外部パラメータ
name の値を Student クラス独自の属性変数
self.name に割り当てることを意味します。
4. 通常の数値と比較すると、クラス内で関数を定義する場合の違いは 1 つだけです。つまり、
最初のパラメーター
クラス自体のインスタンス変数であることです。 self であり、呼び出し時にこのパラメータを渡す必要はありません。また、クラスメソッド(関数)も通常の関数と何ら変わりはなく、デフォルトパラメータ、変数パラメータ、キーワードパラメータを使用することができます (
*argsは可変パラメータ、args 受け取るのはタプルです、**kw はキーワード パラメータであり、kw が受け取るものは dict)。 5. 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
内部属性が外部からアクセスされないようにするには、属性名の前に 2 つのアンダースコア を追加します。Python では、インスタンスの変数名が ## で始まる場合、 #, 内部からのみアクセスでき、外部からはアクセスできないプライベート変数 (private) になっているため、Student クラスを変更しました:
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 には外部からアクセスできなくなります: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">>>> student = Student(&#39;Hugh&#39;, 99)
>>> student.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: &#39;Student&#39; object has no attribute &#39;__name&#39;</pre><div class="contentsignin">ログイン後にコピー</div></div>
これにより、外部コードが内部状態を変更できないことが保証されます。オブジェクトを自由に操作できるため、アクセス制限の保護を通じてコードがより堅牢になります。 しかし、外部コードが名前とスコアを取得したい場合はどうなるでしょうか? get_name や get_score などのメソッドを Student クラスに追加できます。
class Student(object): ... def get_name(self): return self.__name def get_score(self): return self.__score
外部コードによるスコアの変更を許可したい場合はどうすればよいでしょうか? set_score メソッドを Student クラスに追加できます。
class Student(object): ... def set_score(self, score): self.__score = score
Python では、変数名は
__xxx__に似ていることに注意してください。つまり、変数名は 2 つのアンダースコアで始まり、最後に続きます。特殊な変数です。特殊な変数はプライベート変数ではなく、直接アクセスできます。したがって、
__name__ や __score__
などの変数名は使用できません。 _name など、アンダースコアで始まるインスタンス変数名が表示されることがあります。このようなインスタンス変数には外部からアクセスできます。ただし、規則によれば、このような変数が表示されるときは、「」を意味します。アクセスは可能ですが、プライベート変数として扱い、勝手にアクセスしないでください。」
を Student クラスにいつでも追加できることです。 ,
get_grade メソッドは、内部実装の詳細を知らなくても、インスタンス変数に対して直接呼び出すことができます: 6、 从上面的例子中可以很明显的看出,self代表的是类的实例。而 运行结果如下: Traceback (most recent call last): 运行时提醒错误如下:ppr在定义时没有参数,但是我们运行时强行传了一个参数。 由于上面解释过了t.ppr()等同于Test.ppr(t),所以程序提醒我们多传了一个参数t。 这里实际上已经部分说明了 当然,如果我们的定义和调用时均不传类实例是可以的,这就是类方法。 (3)、在继承时,传入的是哪个实例,就是那个传入的实例,而不是指定义了self的类的实例。 运行结果: <__main__.Child object at 0x0000000002A47080> 解释: (4)、在描述符类中,self指的是描述符类的实例 运行结果如下: self in Test: <__main__.Test object at 0x0000000002A570B8> 这里主要的疑问应该在:Desc类中定义的self不是应该是调用它的实例t吗?怎么变成了Desc类的实例了呢? 那么我们如果直接通过类来调用属性x也可以得到相同的结果。 下面是把t.x改为Test.x运行的结果。 以上がPythonでselfを使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。>>> student.get_grade()
'A'
self
的仔细用法
(1)、self代表类的实例,而非类。class Test:
def ppr(self):
print(self)
print(self.__class__)
t = Test()
t.ppr()
执行结果:
<__main__.Test object at 0x000000000284E080>
<class '__main__.Test'>
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()
File "cl.py", line 6, in
t.ppr()
TypeError: ppr() takes 0 positional arguments but 1 was givenself
在定义时不可以省略。class Test:
def ppr():
print(__class__)
Test.ppr()
运行结果:
<class '__main__.Test'>
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 object at 0x0000000002A47080>
<__main__.Parent object at 0x0000000002A47240>
运行c.cprt()时应该没有理解问题,指的是Child类的实例。
但是在运行c.pprt()时,等同于Child.pprt(c),所以self指的依然是Child类的实例,由于self中没有定义pprt()方法,所以沿着继承树往上找,发现在父类Parent中定义了pprt()方法,所以就会成功调用。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 Desc: <__main__.Desc object at 0x000000000283E208>
<__main__.Desc object at 0x000000000283E208> <__main__.Test object at 0x0000000002A570B8>
因为这里调用的是t.x,也就是说是Test类的实例t的属性x,由于实例t中并没有定义属性x,所以找到了类属性x,而该属性是描述符属性,为Desc类的实例而已,所以此处并没有顶用Test的任何方法。self in Test: <__main__.Test object at 0x00000000022570B8>
self in Desc: <__main__.Desc object at 0x000000000223E208>
<__main__.Desc object at 0x000000000223E208> None <class '__main__.Test'>