Pythonのself
Wordの目的は何ですか?私はそれがそのクラスから作成された特定のオブジェクトを参照していることを理解していますが、それがパラメータとしてすべての関数に明示的に追加される必要がある理由はわかりません。説明すると、Rubyではこれが可能です。
class myClass
def myFunc(name)
@name = name
end
end
これはごく簡単にわかります。しかし、Pythonではself
を含める必要があります。
class myClass:
def myFunc(self, name):
self.name = name
誰もがこれを通して私に話すことができますか?それは私の(確かに限られた)経験で出会ったことではありません。
self.
を使用する必要があるのは、Pythonが@
構文を使用してインスタンス属性を参照しないためです。 Pythonは、メソッドが属するインスタンスをpassedに自動化するが、receivedに自動化しない方法でメソッドを実行することを決定しました。 methodsは、メソッドが呼び出されるインスタンスです。これにより、メソッドは関数とまったく同じになり、使用する実際の名前はあなたに任されます(ただし、self
が慣習であり、他の何かを使用すると一般的に人々はあなたに眉をひそめます。)self
はコードにとって特別なものではなく、単なる別のオブジェクトです。
Pythonは、通常の名前と属性を区別するために何か他のことを行うことができました-Rubyのような特別な構文、C++やJava doのような宣言、またはおそらくもっと異なる何かを必要とします-しなかった。 Pythonはすべてを明確にするためのものであり、何が何であるかを明確にし、どこでも完全にそれを行うわけではありませんが、インスタンス属性に対してはそれを行います。インスタンス属性に割り当てるには、どのインスタンスに割り当てるかを知る必要があり、それがself.
を必要とする理由です。
単純なベクトルクラスを見てみましょう:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
長さを計算する方法が欲しいのです。クラス内で定義したいとしたらどうでしょうか。
def length(self):
return math.sqrt(self.x ** 2 + self.y ** 2)
グローバルなメソッド/関数として定義したとしたら、どのように見えるでしょうか。
def length_global(vector):
return math.sqrt(vector.x ** 2 + vector.y ** 2)
そのため、全体の構造は変わりません。どうすればこれを利用できますか? length
クラスのVector
メソッドを書いていないと少しの間仮定すれば、こうすることができます。
Vector.length_new = length_global
v = Vector(3, 4)
print(v.length_new()) # 5.0
これはlength_global
の最初のパラメータがlength_new
のself
パラメータとして再利用できるのでうまくいきます。これは明示的なself
がなければ不可能です。
明示的なself
の必要性を理解するもう1つの方法は、Pythonがどこに構文糖を追加したかを調べることです。あなたが心に留めておくと、それは基本的に、のような呼び出し
v_instance.length()
内部的にに変換されます
Vector.length(v_instance)
self
がどこに当てはまるかは簡単にわかります。実際には、Pythonでインスタンスメソッドを書くことはしません。あなたが書くものは最初のパラメータとしてインスタンスを取らなければならないクラスメソッドです。したがって、インスタンスパラメータを明示的にどこかに配置する必要があります。
次のように定義されたメソッドClassA
を含むクラスmethodA
があるとしましょう。
def methodA(self, arg1, arg2):
# do something
そしてObjectA
はこのクラスのインスタンスです。
ObjectA.methodA(arg1, arg2)
が呼び出されると、pythonはそれを内部的に変換します。
ClassA.methodA(ObjectA, arg1, arg2)
self
変数はオブジェクト自体を参照します。
オブジェクトがインスタンス化されると、そのオブジェクト自体がselfパラメータに渡されます。
このため、オブジェクトのデータはオブジェクトにバインドされています。以下は、各オブジェクトのデータがどのように見えるかを視覚化する方法の例です。 selfがオブジェクト名に置き換えられていることに注目してください。この下の例の図が完全に正確であるとは言っていませんが、うまくいけばselfの使用を視覚化することに役立ちます。
オブジェクトが自身のデータを保持できるように、オブジェクトはselfパラメータに渡されます。
これは完全に正確というわけではないかもしれませんが、次のようにオブジェクトをインスタンス化するプロセスを考えてみましょう。 selfパラメータに独自の名前を渡さないと、クラス内の属性とメソッドは一般的なテンプレートのままになり、オブジェクトを参照する(所属する)ことはありません。そのため、オブジェクトの名前をselfパラメータに渡すことで、1つのクラスから100個のオブジェクトがインスタンス化された場合、それらすべてが独自のデータとメソッドを追跡できます。
下の図を参照してください。
私はこの例が好きです:
class A:
foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: [5]
class A:
def __init__(self):
self.foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: []
はクラスを使わない :
def state_init(state):
state['field'] = 'init'
def state_add(state, x):
state['field'] += x
def state_mult(state, x):
state['field'] *= x
def state_getField(state):
return state['field']
myself = {}
state_init(myself)
state_add(myself, 'added')
state_mult(myself, 2)
print( state_getField(myself) )
#--> 'initaddedinitadded'
クラスは、常にこの「状態」のもの(および初期化、クラス構成、めったに必要とされないメタクラス、および演算子をオーバーライドするためのカスタムメソッドのサポートなどの他のいいもの)を渡さないようにするための方法です。
それでは、組み込みのPythonクラス機構を使って上記のコードをデモンストレーションしましょう。
class State(object):
def __init__(self):
self.field = 'init'
def add(self, x):
self.field += x
def mult(self, x):
self.field *= x
s = State()
s.add('added') # self is implicitly passed in
s.mult(2) # self is implicitly passed in
print( s.field )
[重複した質問から回答を移行しました]
次の抜粋は Pythonに関するselfのドキュメント からの抜粋です。
Modula-3のように、そのメソッドからオブジェクトのメンバを参照するための略語はありません。メソッド関数は、オブジェクトを表す明示的な最初の引数で宣言されます。
多くの場合、メソッドの最初の引数はselfと呼ばれます。これは単なる慣例にすぎません。selfという名前は、Pythonにとって特別な意味はありません。ただし、この規則に従わないと、他のPythonプログラマーにとってコードが読みにくくなる可能性があり、そのような規則に依存するクラスブラウザプログラムを記述することも考えられます。
詳しくは、 クラスに関するPythonのドキュメントチュートリアル を参照してください。
すでに述べた他のすべての理由と同様に、オーバーライドされたメソッドへのアクセスを容易にします。 Class.some_method(inst)
を呼び出すことができます。
便利な場所の例
class C1(object):
def __init__(self):
print "C1 init"
class C2(C1):
def __init__(self): #overrides C1.__init__
print "C2 init"
C1.__init__(self) #but we still want C1 to init the class too
>>> C2()
"C2 init"
"C1 init"
その使用方法は、Javaでのthis
キーワードの使用方法に似ています。つまり、現在のオブジェクトへの参照を与えるためです。
Pythonは、JavaやC++とは異なり、オブジェクト指向プログラミング用に構築された言語ではありません。
Pythonで静的メソッドを呼び出すときは、その中に通常の引数を持つメソッドを書くだけです。
class Animal():
def staticMethod():
print "This is a static method"
ただし、この場合はAnimalである変数を作成する必要があるオブジェクトメソッドには、self引数が必要です。
class Animal():
def objectMethod(self):
print "This is an object method which needs an instance of a class"
Selfメソッドはクラス内の可変フィールドを参照するためにも使用されます。
class Animal():
#animalName made in constructor
def Animal(self):
self.animalName = "";
def getAnimalName(self):
return self.animalName
この場合、selfはクラス全体のanimalName変数を参照しています。注意:メソッド内に変数がある場合、selfは機能しません。その変数は、そのメソッドが実行されている間だけ存在します。フィールド(クラス全体の変数)を定義するには、クラスメソッドの外側でそれらを定義する必要があります。
私が言っていることの1つの単語がわからない場合は、Googleの「Object Oriented Programming」。これを理解すれば、その質問をする必要すらありません:)。
Pythonの禅に従うのは「明示的な方が暗黙的より優れている」ということです。それは確かにあなたのクラスオブジェクトへの参照です。たとえば、JavaやPHPでは、this
と呼ばれています。
user_type_name
があなたのモデルのフィールドであるならば、あなたはself.user_type_name
によってそれにアクセスします。
まず第一に、selfは慣習的な名前であり、その代わりに他の何か(首尾一貫した)を置くことができます。
それはオブジェクト自身を参照するので、あなたがそれを使用しているとき、あなたは.nameと.ageがあなたが作成しようとしているStudentオブジェクトのプロパティであることを宣言しています。
class Student:
#called each time you create a new Student instance
def __init__(self,name,age): #special method to initialize
self.name=name
self.age=age
def __str__(self): #special method called for example when you use print
return "Student %s is %s years old" %(self.name,self.age)
def call(self, msg): #silly example for custom method
return ("Hey, %s! "+msg) %self.name
#initializing two instances of the student class
bob=Student("Bob",20)
alice=Student("Alice",19)
#using them
print bob.name
print bob.age
print alice #this one only works if you define the __str__ method
print alice.call("Come here!") #notice you don't put a value for self
#you can modify attributes, like when alice ages
alice.age=20
print alice
self
は、オブジェクト自体へのオブジェクト参照です。したがって、それらは同じです。 Pythonメソッドはオブジェクト自体のコンテキストでは呼び出されません。 Pythonのself
はカスタムオブジェクトモデルか何かを扱うために使われるかもしれません。
だれもLuaを立ち上げていないのは驚きです。 Luaは 'self'変数も使用しますが、省略することもできますが、まだ使用されています。 C++は、これと同じことを行います。それぞれの関数で 'self'を宣言しなければならない理由はありませんが、luaとC++でできるのと同じようにそれを使用できるはずです。簡潔であることに誇りを持っている言語にとって、それはあなたが自己変数を宣言することを要求することは奇妙です。
Pythonが設計されている方法では、代替手段はほとんど機能しないからです。 Pythonは、暗黙のthis
(a-la Java/C++)または明示的な@
(a-la Ruby)の両方が機能しないコンテキストでメソッドまたは関数を定義できるように設計されています。 Pythonの規約を使った明示的なアプローチの例を見てみましょう:
def fubar(x):
self.x = x
class C:
frob = fubar
fubar
はグローバル変数であると仮定するので(そしてself
でも)、frob
関数は機能しません。代わりの方法は、置き換えられたグローバルスコープでメソッドを実行することです(self
はオブジェクトです)。
暗黙のアプローチは、
def fubar(x)
myX = x
class C:
frob = fubar
これは、myX
がfubar
(およびfrob
)でもローカル変数として解釈されることを意味します。ここでの代替策は、呼び出しの間に保持される置き換えられたローカルスコープでメソッドを実行することですが、それはメソッドローカル変数の可能性を削除するでしょう。
しかし、現在の状況はうまくいきます。
def fubar(self, x)
self.x = x
class C:
frob = fubar
ここでメソッドとして呼び出されると、frob
はself
パラメータを介して呼び出されたオブジェクトを受け取り、fubar
はオブジェクトとしてパラメータとして呼び出すことができ、同じように機能します( は C.frob
と同じです) ).
次の例を見てください。これはself
の目的を明確に説明しています。
class Restaurant(object):
bankrupt = False
def open_branch(self):
if not self.bankrupt:
print("branch opened")
#create instance1
>>> x = Restaurant()
>>> x.bankrupt
False
#create instance2
>>> y = Restaurant()
>>> y.bankrupt = True
>>> y.bankrupt
True
>>> x.bankrupt
False
self
は、インスタンス間を区別するために使用される/必要とされます。
従来はself
と呼ばれていた引数の使用は、なぜそれが必要なのか、理解するのがそれほど難しくありません。それともなぜそれを明示的に言及するのか?それは、私がこの質問を探すほとんどのユーザーにとってより大きな質問であるか、そうでなければ、彼らはpythonを学ぶのと同じ質問をするでしょう。私は彼らにこれらのブログを読むことを勧めます:
これはキーワードではありません。
Initを含むすべてのクラスメソッドの最初の引数は、常にクラスの現在のインスタンスへの参照です。慣例により、この引数は常にselfという名前です。 initメソッドでは、selfは新しく作成されたオブジェクトを参照します。他のクラスメソッドでは、メソッドが呼び出されたインスタンスを参照します。例えば、以下のコードは上記のコードと同じです。
2:なぜ私たちはこのようにしているのでしょうか、そしてなぜJavaのようにそれを引数として排除できず、代わりにキーワードを持っているのでしょう
もう1つ追加したいのは、オプションのself
引数を使用すると、self
を記述しなくてもクラス内で静的メソッドを宣言できるようになることです。
コード例:
class MyClass():
def staticMethod():
print "This is a static method"
def objectMethod(self):
print "This is an object method which needs an instance of a class, and that is what self refers to"
_ ps _ :これはPython 3.xでのみ機能します。
以前のバージョンでは、明示的に@staticmethod
デコレータを追加する必要があります。それ以外の場合はself
引数は必須です。
__init__
メソッドでは、selfは新しく作成されたオブジェクトを参照します。他のクラスメソッドでは、メソッドが呼び出されたインスタンスを参照します。
selfは、名前として、単なる慣例です。必要に応じて呼び出してください。しかし、それを使うとき、例えばオブジェクトを削除するとき、あなたは同じ名前を使う必要があります:__del__(var)
、ここでvar
は__init__(var,[...])
で使われました
全体図を持つには、cls
も見てください。この post は役に立ちます。
self
name__は避けられません。questionself
name__は暗黙的または明示的であるべきです。 Guido van Rossum
はこの問題を解決し、 self
name__は のままにする必要があると言っています。
self
name__はどこに住んでいますか?もし関数型プログラミングだけに固執すればself
name__は必要ないでしょう。 Python OOPと入力すると、そこにself
name__が見つかります。
これは、メソッドclass C
を持つ典型的なユースケースm1
です。
class C:
def m1(self, arg):
print(self, ' inside')
pass
ci =C()
print(ci, ' outside')
ci.m1(None)
print(hex(id(ci))) # hex memory address
このプログラムは出力します:
<__main__.C object at 0x000002B9D79C6CC0> outside
<__main__.C object at 0x000002B9D79C6CC0> inside
0x2b9d79c6cc0
そのためself
name__はクラスインスタンスのメモリアドレスを保持します。 self
name__の目的は、インスタンスメソッドの参照を保持し、その参照への 明示的 アクセスを持つことになります。
クラスメソッドには3つの異なるタイプがあります。