ホームページ >バックエンド開発 >Python チュートリアル >Python での self の使用法を理解する

Python での self の使用法を理解する

高洛峰
高洛峰オリジナル
2017-03-03 15:17:261622ブラウズ

私が初めて Python でクラスの書き方を学び始めたとき、それが非常に面倒だと感じました。なぜ、定義するときに必要なのに、呼び出すときに必要ないのですか。なぜ、キーストロークの数を減らすために内部的に簡素化できないのでしょうか?この記事を読めば、あなたの疑問はすべて理解できるでしょう。

self はクラスではなく、クラスのインスタンスを表します。

説明する例:

class Test:
  def prt(self):
    print(self)
    print(self.__class__)
 
t = Test()
t.prt()

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

<__main__.Test object at 0x000000000284E080>
<class &#39;__main__.Test&#39;>

上記の例から、self がクラスのインスタンスを表すことは明らかです。そして self.class はクラスを指します。

selfはselfと書く必要はありません

多くの子供たちは最初に他の言語を学び、その後Pythonを学ぶので、常にselfをこのように書きたいのですが、大丈夫ですか?

もちろん、上記のコードを書き直してみましょう。

class Test:
  def prt(this):
    print(this)
    print(this.__class__)
 
t = Test()
t.prt()

をこれに変更すると、実行結果はまったく同じになります。

もちろん、確立された習慣を尊重し、自己を使用することが最善です。

self と書かないことはできますか

Python インタプリタ内で t.prt() を呼び出すと、Python は実際にそれを Test.prt(t) として解釈します。これは、 self を class のインスタンスに置き換えることを意味します。

興味のあるお子様は、上記の t.prt() 行を書き直すことができます。実行後の実際の結果はまったく同じになります。

実際、定義時に self を省略できないことは部分的に説明されていますので、試してみる必要がある場合は、以下を参照してください:

class Test:
  def prt():
    print(self)
 
t = Test()
t.prt()

実行時のリマインダーエラーは次のとおりです: prt には定義時にパラメータがありません。 , しかし、実行するとパラメータが強制的に渡されました。

t.prt() は Test.prt(t) と同等であると上で説明したため、プログラムは追加のパラメーター t を渡したことを思い出させます。

Traceback (most recent call last):
 File "h.py", line 6, in <module>
  t.prt()
TypeError: prt() takes 0 positional arguments but 1 was given

もちろん、定義でクラスインスタンスを渡さなくても大丈夫です。これはクラスメソッドです。

class Test:
  def prt():
    print(__class__)
Test.prt()

実行結果は以下の通り

<class &#39;__main__.Test&#39;>

継承する際にどのインスタンスに渡されるかは、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 object at 0x0000000002A47080>
<__main__.Child object at 0x0000000002A47080>
<__main__.Parent object at 0x0000000002A47240>

説明:

インスタンスを参照する c.cprt() を実行するときに、理解に問題はありません。チャイルドクラスの。

しかし、c.pprt() を実行する場合、それは Child.pprt(c) と同等であるため、self は依然として Child クラスのインスタンスを参照します。pprt() メソッドは self 内で定義されていないため、調べる必要があります。継承ツリーを遡ると、pprt() メソッドが親クラス Parent に定義されていることがわかり、このメソッドは正常に呼び出されます。

記述子クラスでは、self は記述子クラスのインスタンスを参照します

まず例を見てみましょう:

class Desc:
  def __get__(self, ins, cls):
    print(&#39;self in Desc: %s &#39; % self )
    print(self, ins, cls)
class Test:
  x = Desc()
  def prt(self):
    print(&#39;self in Test: %s&#39; % self)
t = Test()
t.prt()
t.x

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

self in Test: <__main__.Test object at 0x0000000002A570B8>
self in Desc: <__main__.Desc object at 0x000000000283E208>
<__main__.Desc object at 0x000000000283E208> <__main__.Test object at 0x0000000002A570B8> <class &#39;__main__.Test&#39;>

ほとんどの子供用靴は、なぜ Desc クラスで定義された self をそれを呼び出すインスタンス t にしてはいけないのかという疑問を持ち始めています。どのようにして Desc クラスのインスタンスになったのでしょうか?

注: ここで呼ばれているのは t.x です。これは、Test クラスのインスタンス t の属性 x であることを意味します。属性 x はインスタンス t で定義されていないため、クラス属性 x が見つかりました。この属性は Desc クラスのインスタンスである記述子属性であるため、ここには Test を使用するメソッドはありません。

次に、クラスを通じて属性 x を直接呼び出しても、同じ結果が得られます。

以下はt.xをTest.xに変更した結果です。

self in Test: <__main__.Test object at 0x00000000022570B8>
self in Desc: <__main__.Desc object at 0x000000000223E208>
<__main__.Desc object at 0x000000000223E208> None <class &#39;__main__.Test&#39;>

余談: 多くの場合、記述子クラスは記述子を呼び出すインスタンスが誰であるかを知る必要があるため、記述子クラスにはインスタンスを呼び出すクラスを表す 2 番目のパラメーター ins があります。 t.x の 3 行目の実行結果の 2 番目の項目が 0004ee041c80c39817d2de1bc325e5f7 であることがわかります。 Test.x を使用して呼び出した場合、インスタンスがないため None が返されます。

OOの本質からPythonで自己を理解する

たとえば、ユーザーのデータを操作したいとします。ユーザーのデータには名前と年齢が含まれています。プロセス指向を使用する場合、実装は次のようになります。

def user_init(user,name,age): 
  user[&#39;name&#39;] = name 
  user[&#39;age&#39;] = age 
 
def set_user_name(user, x): 
  user[&#39;name&#39;] = x 
 
def set_user_age(user, x): 
  user[&#39;age&#39;] = x 
 
def get_user_name(user): 
  return user[&#39;name&#39;] 
 
def get_user_age(user): 
  return user[&#39;age&#39;] 
 
myself = {} 
user_init(myself,&#39;kzc&#39;,17) 
print get_user_age(myself) 
set_user_age(myself,20) 
print get_user_age(myself)

ユーザーに対するさまざまな操作にはユーザー パラメーターを渡す必要があることがわかります。

オブジェクト指向を使用する場合、ユーザー パラメーターを毎回やり取りする必要はありません。関連するデータと操作を 1 か所でバインドでき、このクラスのさまざまな場所からデータを簡単に取得できます。

データがクラス内のさまざまな場所からアクセスできる理由は、データが self にバインドされているためです。もちろん、そのメソッドの最初のパラメーターを self と呼ぶ必要はなく、単に Self という別の名前を付けることができます。大会。
以下はオブジェクト指向の実装であり、より構造化されており、明確で読みやすいことがわかります。

class User(object): 
  def __init__(self,name,age): 
    self.name = name 
    self.age = age 
 
  def SetName(self,name): 
    self.name = name 
 
  def SetAge(self,age): 
    self.age = age 
 
  def GetName(self): 
    return self.name 
 
  def GetAge(self): 
    return self.age 
 
u = User(&#39;kzc&#39;,17) 
print u.GetName() 
print u.GetAge()

上記の例からわかるように、オブジェクト指向は実際には非常に便利ですが、ほとんどの人はそれをうまく抽象化せず、うまくカプセル化せず、間違って使用しています。

概要

    selfは定義時に定義する必要がありますが、呼び出されたときに自動的に渡されます。
  • selfの名前は規定されていませんが、合意に従ってselfを使用するのが最善です
  • self は、呼び出されたときに常にクラスのインスタンスを参照します。

Python での self の使用法の理解に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。