質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

3952閲覧

pythonのクラスの第一引数に書いてるself, object, cls, typeの意味について

sequelanonymous

総合スコア123

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

2グッド

11クリップ

投稿2021/04/21 18:15

下記のサンプルコードの実行結果にあるようにクラスの第一引数に書いてるself, object, cls, typeは、全て同じ機能をもっていると理解しています。
第一引数に取るのは、クラスオブジェクトの基底クラスとなるtypeクラスを継承するために何かしらの引数名を書く必要があると理解しています。
その必要性は、classと定義することでメタクラスを継承するように強制されると理解しています。

上記のわたしの理解に間違いがありましたら、ご指摘いただけませんでしょうか?説明不足の箇所や説明の仕方に間違いがありましたら、ご指摘いただけると助かります。

また、不明なのが、なぜ、self, object, cls, typeの使い分けをする必要があるのか、それぞれ、どういった使い分けをしているかご存知の方いらしたらご教示いただけませんでしょうか?

classobjects.py

python

1class Params(object): 2 def __new__(cls): 3 self = super().__new__(cls) 4 print(f'cls: {cls}') 5 return self 6 7 def __init__(self): 8 print(f'self: {self}') 9 pass 10 11 def __call__(type): 12 print(f'type: {type}') 13 return type 14 15if __name__ == '__main__': 16 p = Params() 17 print(p) 18 print(p())

class Params(object):は、class Params:に書き換えて、せいぜい、つかうとしても、2種類ぐらいの引数名で事足りると思うのですが、どうなんでしょうか。とりわけ、typeとobjectは、いつ利用するかが気になっています。

実行結果

shell

1$ python classobjects.py 2cls: <class '__main__.Params'> 3self: <__main__.Params object at 0x105047c40> 4<__main__.Params object at 0x105047c40> 5type: <__main__.Params object at 0x105047c40> 6<__main__.Params object at 0x105047c40>
nolyzy, Taste_Bitter👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kenji.Noguchi

2021/04/27 00:20

objectはPythonの組み込みの基底クラス, typeは組み込みのタイプクラス、clsは命名規則によるクラスオブジェクト、selfは命名規則によるインスタンスオブジェクトです。Pythonは柔軟なのでこれに従わない命名をすることもできますが、他のPythonプログラマと意思の疎通が困難になります。 newはクラスを引数にメモリを確保するので引数はclsと命名するのが一般的。initはインスタンスを初期化するのでself。`def __call__(type)`という命名は見たことがないです。ここはselfと書くのが普通です。実際中に入るのはインスタンスオブジェクトであってタイプではありませんから。文法で強制されているわけではなくただの命名規則ですけどね。
guest

回答2

0

ベストアンサー

python

1class A(B): 2 pass

class文の引数は親クラスの指定に使います。↑は「AはBを継承する」という宣言です。

関数の引数は呼び出し元からの値に名前を束縛するのに使います。要するにローカル変数です。

機能がぜんぜん違います。


下記のサンプルコードの実行結果にあるようにクラスの第一引数に書いてるself, object, cls, typeは、全て同じ機能をもっていると理解しています。

上記の通り、そんなことはないです。

第一引数に取るのは、クラスオブジェクトの基底クラスとなるtypeクラスを継承するために何かしらの引数名を書く必要があると理解しています。

必要はないです。書かれていない場合はobjectを継承します。

その必要性は、classと定義することでメタクラスを継承するように強制されると理解しています。

意味が通じませんでした。

とりわけ、typeとobjectは、いつ利用するかが気になっています。

typeはPython言語の組み込みクラスと同じ名前なので、慣習としてローカル変数名には使いません。


(追記2)

関数の話をします。

python

1def a(x, y): 2 pass

と宣言すると、まず「引数が2つの関数オブジェクト」が作られます。そしてdef文が実行された名前空間でaという名前を束縛します(つまり、変数aに代入されるということです)。
この関数オブジェクトは2つの引数を受け取ります。

関数が呼び出された時に作られる、関数の本体スイート(ブロックの中)を実行している時だけ存在する名前空間があります。
その名前空間に束縛される名前のことをローカル変数と呼んでいます

関数をa(4, 8)というコードを実行すると、名前aが解決されてオブジェクトが取り出されます(それは関数オブジェクトでした)。
そのオブジェクトを"4と8という2つの引数を伴って呼び出す"という操作がおこなわれます。
関数オブジェクトの呼び出しがおこなわれると、
まず名前空間が作られ、
関数の第1引数である名前xが、呼び出しの第1引数である4に束縛され、
関数の第2引数である名前yが、呼び出しの第2引数である8に束縛されます。
そののち本体が実行されます。
本体を実行している間は実行時の名前空間に名前xyが束縛されています。
ですから定義からしてxyはローカル変数です。

ここで、"引数"という言葉が2種類の対照的な意味で登場していました。
紛らわしいので、
関数側の引数を[仮引数 とか parameter]((https://docs.python.org/ja/3/glossary.html#term-parameter)と呼び、
呼び出し時に渡す引数を実引数 とか argumentと呼んで区別したりしますね。


(追記)

メソッドの話をします。

公式ドキュメントのこのあたりです。
https://docs.python.org/ja/3/reference/datamodel.html?highlight=new#index-36

ちょっと読み進めたところに

インスタンスメソッドオブジェクトが呼び出される際、根底にある関数 (__func__) が呼び出されます。このとき、クラスインスタンス (__self__) が引数リストの先頭に挿入されます。例えば、 C を関数 f() の定義を含むクラス、 xC のインスタンスとすると、 x.f(1) の呼び出しは C.f(x, 1) の呼び出しと同じです。

とでてきます。

python

1class C: 2 def f(self, i): 3 pass

とすると、class文の本体スイートが実行されクラスオブジェクトが作られます。
そしてclass文が実行された名前空間でCという名前を束縛します(つまり、変数Cに代入されるということです)。
クラスオブジェクトが作られた時にそのfという属性は、def文で作成された「引数が2つの関数オブジェクト」に束縛されています。
C.fと参照すると「引数が2つの関数オブジェクト」を指しているというわけです。

python

1x = C()

とインスタンス化して、

python

1x.f(1)

と呼び出すとき、その呼び出しはC.f(x, 1)の呼び出しと同じだと言っています。

実は、x.fは、def文で生成された(C.fで参照できる)関数とは別のオブジェクトに束縛されています。
インスタンスメソッドオブジェクトなるものに束縛されていると説明されていて、そのインスタンスメソッドオブジェクトを(1)という引数で呼び出すとその中でC.f(x, 1)の呼び出しがおこなわれるわけです。
(そのような機能を持っているオブジェクトに対して、"インスタンスメソッドオブジェクト"という名前を付けた、という理解でもいいかもしれません)

前述の通り、C.fdef f(self, i): passで作成された関数オブジェクトでした。
C.f(x, 1)の呼び出しがおこなわれるということは、
その関数の第1引数である名前selfは、メソッドの呼び出し元であるxに束縛され、
その関数の第2引数である名前iは、メソッド呼び出しの第1引数である1に束縛されます。

「selfには自分自身が入る」などとよく説明されますが、その機構は上記のようになっています。


続けて

クラスメソッドオブジェクトからインスタンスメソッドオブジェクトが導出される際、 __self__ に記憶されている "クラスインスタンス" は実際はクラスそのものなので、 x.f(1)C.f(1) の呼び出しは、根底にある関数を f として f(C,1) の呼び出しと等価です。

と書いてあります。

python

1class C: 2 @classmethod 3 def f(cls, i): 4 pass 5 6x = C()

に対してC.f(1)x.f(1)と呼び出しするとき、
その呼び出しは、根底の関数オブジェクトをfとするとf(C, 1)の呼び出しと同じだと言っています。

関数の第1引数である名前clsは、メソッドの呼び出し元(のクラス)であるCに束縛され、
関数の第2引数である名前iは、メソッドの第1引数である1に束縛されます。


https://docs.python.org/ja/3/reference/datamodel.html#object.new

このメソッドは特別扱いされているので、明示的に静的メソッドと宣言する必要はありません

と記載されている通り、__new__は明に書かなくても静的なメソッド(≒クラスメソッド)として扱われることになっています。

投稿2021/04/22 06:04

編集2021/04/24 08:35
quickquip

総合スコア11038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sequelanonymous

2021/04/23 14:11

コメントありがとうございます!一点ご確認させてください。 関数の引数は呼び出し元からの値に名前を束縛するのに使います。 ここに関してですが、上記のコードですと具体的に何と何を束縛することになりますでしょうか?
quickquip

2021/04/24 02:30 編集

Params() で __new__ の cls を束縛するのはクラスオブジェクトParams(=名前Paramsを束縛しているクラスオブジェクト) __init__ の self を束縛するのは、__new__の返り値である「Params のインスタンス」 p() で __call__ の self を束縛するのはインスタンスオブジェクトp(=名前pを束縛しているオブジェクト)
sequelanonymous

2021/04/24 07:45

追記コメントありがとうございます!そして、何がなにを束縛しているかについて理解できました。 すみませんが、追記コメントに関して追加でご確認させてください。 ーー 1)下記のa, bは、x, yの間違いでしょうか? 関数の第1引数である名前aが、呼び出しの第1引数である4に束縛され、 関数の第2引数である名前bが、呼び出しの第2引数である8に束縛されます。 2) 引数に値を渡すのは、変数代入と同じことをやっていて、つまり束縛している、理解しまいた。 つまり、例えば、 def test(a, b) pass test(1,2) と a = 1 b = 2 は、束縛するという意味では同じことだと理解しました。 この理解はあっていますでしょうか? 3) 上記の前提をもとにselfの実態を整理すると、 x.f(1) の呼び出しは C.f(x, 1) の呼び出しと同じで、呼び出したときに、classの基底クラスであるobject クラス内にある関数 (__func__) が呼び出され、このとき、クラスインスタンス (__self__) が引数リストの先頭に挿入される、という理解であっていますでしょうか? クラスインスタンス (__self__)がいきなりどこからでてきたのかは、理解できずにいます。
quickquip

2021/04/24 08:44 編集

1) その通りです。すみません。修正しました。 2) 合っていると思います。a,b への束縛が関数本体が実行される前に起こっています。 3) "classの基底クラスであるobject クラス内にある関数" の部分が間違ってます。説明だけが登場して、定義は明にされていない「インスタンスメソッドオブジェクト」なるクラスがどこかで定義されている、と考えてください。__self__ も __func__ もその「インスタンスメソッドオブジェクト」の持ち物ですが、その"内部実装で使われている名前"はさほど重要じゃありません。
quickquip

2021/04/24 08:44

「説明だけで中身は詳細に話さないけど、こういうものがあると思ってね」という、いったんブラックボックスにして説明が進む場面が苦手なのかなと感じました。そういった概念が登場すると「すでに説明されている別の何か」と結びつけてしまう傾向があるように思いました。(雑な感想ですみませんが)
quickquip

2021/04/25 11:50

> class文の引数は親クラスの指定に使います。↑は「AはBを継承する」という宣言です。 > 関数の引数は呼び出し元からの値に名前を束縛するのに使います。要するにローカル変数です。 > 機能がぜんぜん違います ここを読んでもらえてないような気がします。
guest

0

  • class Params(object):

python2では基底classとしてobjectを明示的に書く必要がありましたが、python3では不要となりました。

  • 2種類ぐらいの引数名で事足りると思うのですが、どうなんでしょうか。

text

1__new__やクラスメソッドの第一引数でclsを使ったり、 2インスタンスメソッドの第一引数でselfを使うのは、読みやすさのための慣習です。 3__call__(type)という書き方は慣習としては行いません。__call__(self)が慣習です。 4慣習ですので、どういう名前を使っても動作には影響ありません。

投稿2021/04/21 19:12

ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sequelanonymous

2021/04/21 19:31

ありがとうございます!インスタンスメソッドの第一引数にはいるのは、typeクラスを継承しているという理解はあっていますでしょうか?だとしたら、なぜpython2ではobjectという引数名をつかっていたのか、きになるのと、python3でもあんまり第一引数にtypeという引数名を利用してるのをあんまり見かけないのはなぜかきになります。 また、第一引数にクラス自身がはいる、という説明文をよくみかけますが、__main__にバインドされるタイミングでクラス定義が読み込まれ、__dict__にglobal空間だけ保存されたクラスが第一引数にはいる、という意味合いだとおもいますでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問