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

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

ただいまの
回答率

87.34%

pythonのクラスのインスタンス化したときの挙動とインスタンス化方法について

解決済

回答 3

投稿

  • 評価
  • クリップ 4
  • VIEW 653

score 123

上記、タイトルのことを確認しています。
下記のサンプルコードを一つずつ挙動確認しながら理解できないことを書いていきました。なにかお気づきの点がありましたらご教示いただけませんでしょうか?

サンプルコード singleton.py

class SpecialMethods:
    print("class variable")

    def __init__(self):
        print(f"__init__: {self}")

    def __new__(cls):
        self = super().__new__(cls)
        print(f"cls of __new__: {cls}")
        print(f"self of __new__: {self}")
        return self

    def __call__(self):
        print(f"__call__: {self}")

    def _type(type):
        print(f"type: {type}")

    def _self(self):
        print(f"self: {self}")
        return type(self)

    def _cls(cls):
        print(f"cls: {cls}")
        return type(cls)

コンソール

>>> from singleton import SpecialMethods
class variable


1)なぜ、importした瞬間にprint文の出力がでるのでしょうか?

>>> sm = SpecialMethods
>>> sm()
cls of __new__: <class 'singleton.SpecialMethods'>
self of __new__: <singleton.SpecialMethods object at 0x10d304f40>
__init__: <singleton.SpecialMethods object at 0x10d304f40>
<singleton.SpecialMethods object at 0x10d304f40>
>>> type(sm)
<class 'type'>
>>> 

2)通常であれば、sm = SpecialMethods()のように括弧付きで変数にいれることでクラスのインスタンス化ができるはずですが、かっこなしで変数にいれたあとにカッコつけることでインスタンス化することができるのでしょうか?
3)また、その場合、かっこなしでのsm及びSpecialMethodsは、なにものなんでしょうか?クラスオブジェクトといえばいいでしょうか?また、そのクラスオブジェクトの型が<class 'type'>になっていって、これは何を指しているのでしょうか?

>>> sm_fn = SpecialMethods()
cls of __new__: <class 'singleton.SpecialMethods'>
self of __new__: <singleton.SpecialMethods object at 0x10d304f40>
__init__: <singleton.SpecialMethods object at 0x10d304f40>
>>> sm_fn._type()
type: <singleton.SpecialMethods object at 0x10d304f40>
>>> sm_fn._self()
self: <singleton.SpecialMethods object at 0x10d304f40>
<class 'singleton.SpecialMethods'>
>>> sm_fn._cls()
cls: <singleton.SpecialMethods object at 0x10d304f40>
<class 'singleton.SpecialMethods'>


4)<class 'singleton.SpecialMethods'>は、type()でかえってきた型のはずですが、型名でもなくただのクラス名を返しています。これは何を意味しているのでしょうか?

上記と同じコードを下記のようにpythonコマンドを実行した場合

...
...
...
if __name__ == '__main__':

    ss = SpecialMethods()
    print(ss())
    print(ss)
    print(ss._type())
    print(ss._self())
    print(ss._cls())
$ python singleton.py
class variable
cls of __new__: <class '__main__.SpecialMethods'>
self of __new__: <__main__.SpecialMethods object at 0x108bf8f70>
__init__: <__main__.SpecialMethods object at 0x108bf8f70>
__call__: <__main__.SpecialMethods object at 0x108bf8f70>
None
<__main__.SpecialMethods object at 0x108bf8f70>
type: <__main__.SpecialMethods object at 0x108bf8f70>
None
self: <__main__.SpecialMethods object at 0x108bf8f70>
<class '__main__.SpecialMethods'>
cls: <__main__.SpecialMethods object at 0x108bf8f70>
<class '__main__.SpecialMethods'>

5)インスタンス化した場合は、typeの結果がmain.となりますが、<class 'main.SpecialMethods'>の部分の、main.は何を指していてい、なぜでてくるのでしょうか?

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

以下の説明を理解するためには、かなりの知識が必要です。
分からないとところはネットで調べるか、質問して下さい。

  • 1)なぜ、importした瞬間にprint文の出力がでるのでしょうか?

from singleton import SpecialMethodsを実行するとsingleton.pyがimportされているかどうかを確認し、importされていなければsingleton.pyをインポートして、SpecialMethodsという変数にsingleton.SpecialMethodsをバインドします。
singleton.pyがimportされるとき、SpecialMethodsのクラス定義が実行されます。クラス定義の中のコードは、名前空間をクラスSpecialMethodsとして実行されます。ここで、print("class variable")が実行されるのでclass variableが印字されます。
もし、もう一度from singleton import SpecialMethodsを実行した場合は、既にインポート済みなので、print("class variable")が実行されません。

  • 2)通常であれば、sm = SpecialMethods()のように括弧付きで変数にいれることでクラスのインスタンス化ができるはずですが、かっこなしで変数にいれたあとにカッコつけることでインスタンス化することができるのでしょうか?

Pythonの変数は、文字列とオブエジェクトのバインドです。
SpecialMethodsという変数は、クラスそのものではなく、そのクラスとバインドされている文字列です。sm = SpecialMethods は、"sm"という文字列を”SpecialMethods”という文字列にバインドされているオブジェクト(この場合にはクラスオブジェクト)をバインドしただけです。
SpecialMethods()は文字列"SpecialMethod”にバインドされているクラスオブジェクトのインスタンスを作成するという処理であり、変数名とは関係ありません。したがって、sm = SpecialMethodsを実行した後であれば、sm()でも同じことが起こります。

  • 3)また、その場合、かっこなしでのsm及びSpecialMethodsは、なにものなんでしょうか?クラスオブジェクトといえばいいでしょうか?

はい。そうです。

  • また、そのクラスオブジェクトの型が<class 'type'>になっていって、これは何を指しているのでしょうか?

typeはクラスのクラスです。メタクラスとも呼びます。
pythonの全てのクラスはtypeまたはtypeの派生クラスのインスタンスです。

  • 4)<class 'singleton.SpecialMethods'>は、type()でかえってきた型のはずですが、型名でもなくただのクラス名を返しています。これは何を意味しているのでしょうか?

pythonでは、クラスと型は同じ意味です。従って型名とクラス名は同じです。

  • 5)インスタンス化した場合は、typeの結果がmain.となりますが、<class 'main.SpecialMethods'>の部分の、main.は何を指していてい、なぜでてくるのでしょうか?
$ python singleton.py
として起動した場合、モジュール名は__main__となります。
<class '__main__.SpecialMethods'>は__main__SpecialMethodsというクラスを表示したものです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/04/21 13:04

    ご回答ありがとうございます!一点ご確認させてください。
    ご回答のなかで頻繁に言及されてるバインドとはどういう意味でしょうか?
    なんとなく雰囲気では理解しましたが、より具体的にどういう処理のことをバインドと解釈したらよろしいでしょうか?

    > Pythonの変数は、文字列とオブエジェクトのバインドです。
    また、文字列(str)もオブジェクトですし、ここでいうオブジェクトは、なんのことを言っていますでしょうか?

    キャンセル

  • 2021/04/21 16:57

    bindとはヒモで縛るというような意味です。日本語の公式ドキュメントでは束縛と訳していますね。
    https://docs.python.org/ja/3/reference/executionmodel.html?highlight=%E6%9D%9F%E7%B8%9B#naming-and-binding
    をご覧ください。
    実装上は辞書を使って行うことが多いですが、python処理系によって違っても良いことになっています。
    普通のグローバル変数の変数名と値のバインドはglobals()が返す辞書で行っています。

    キャンセル

  • 2021/04/22 02:52

    ありがとうございます!ドキュメント読んで理解できました!

    キャンセル

+1

  • 1
    クラスのスイートは実行されるからです。

次にクラスのスイートが、新たな実行フレーム (名前づけと束縛 (naming and binding) を参照してください) 内で、新たに作られたローカル名前空間と元々のグローバル名前空間を使って実行されます (通常、このスイートには主に関数定義が含まれます)。
8. 複合文 (compound statement) — Python 3.9.4 ドキュメント

  • 2
    できます。


  • リファレンスに準拠するのであれば、クラスオブジェクトないし型オブジェクトで良いと思います。また、クラスオブジェクトはtypeクラスのインスタンスです

次に、継承リストを基底クラスに、保存されたローカル名前空間を属性値辞書に、それぞれ使ってクラスオブジェクトが生成されます。最後に、もとのローカル名前空間において、クラス名がこのクラスオブジェクトに束縛されます。
8. 複合文 (compound statement) — Python 3.9.4 ドキュメント

  • 4
    Pythonのオブジェクト指向においては原則的には型=クラスです。

引数が1つだけの場合、object の型を返します。返り値は型オブジェクトで、一般に object.class によって返されるのと同じオブジェクトです。
組み込み関数 — Python 3.9.4 ドキュメント | type

  • 5
    まず型オブジェクトはreprによって文字列化されているのが前提です。

この関数は多くの型について、 eval() に渡されたときと同じ値を持つようなオブジェクトを表す文字列を生成しようとします。そうでない場合は、山括弧に囲まれたオブジェクトの型の名前と追加の情報 (大抵の場合はオブジェクトの名前とアドレスを含みます) を返します。
組み込み関数 — Python 3.9.4 ドキュメント | repr

__main__はトップレベルモジュールですね。

main --- トップレベルのスクリプト環境 — Python 3.9.4 ドキュメント

山括弧で囲まれた中には、アドレスが表示されています。__main__は所属する名前空間ということになります。


真面目にPythonの言語仕様を勉強することが目的であれば、リファレンスの以下の項の通読をおすすめします。

通読まではしないとしても、言語仕様や組み込み関数・型の挙動等でわからないことがあったらこの辺りを確認する癖をつけると良いと思います。だいたいのことは書いてあります。

また、こちらのサイトもおすすめしておきます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/04/22 02:55

    ありがとうございます!ここで言われてる型オブジェクトとは、具体的に何を指していますでしょうか?

    キャンセル

0

解決済みのようですが、少しだけ補足です。

質問文にある、実行されるクラスのコードは以下の通りになってます。

class SpecialMethods:
    # (省略)
    def _type(type):
        print(f"type: {type}")

    def _self(self):
        print(f"self: {self}")
        return type(self)

    def _cls(cls):
        print(f"cls: {cls}")
        return type(cls)

ソースコードで「_type()」「_self()」「_cls()」はどれもメソッドの第一引数をprint文で表示しています。インスタンスメソッドでは、第一引数にはクラスインスタンスが渡されます(@classmethodデコレータを使った場合など、違う状況もありますが)。第一引数名を「type」「self」「cls」の何にしたところで変わりません。

なお、慣例的にインスタンスメソッドでは「self」、クラスメソッドでは「cls」を第一引数名に使うことが多いようです。

3. データモデル - Python 3.9.4 ドキュメントには以下のように説明されています。

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

インスタンスメソッドで、インスタンス、クラスを使い分けたいときは、第一引数の名前を変えるのではなく、第一引数の属性などを使ってアクセスしてください。以下、簡単な例です。

>>> class c1():
...   def f1(self):
...     print("self: {}".format(self))
...     print("type(self): {}".format(type(self)))
...     print("self.__class__: {}".format(self.__class__))
...   @classmethod
...   def f2(cls):
...     print("classmethod cls: {}".format(cls))
...
>>>
>>>
>>>
>>> ins1 = c1()
>>> ins1.f1()
self: <__main__.c1 object at 0x7fa43f39e048>
type(self): <class '__main__.c1'>
self.__class__: <class '__main__.c1'>
>>> ins1.f2()
classmethod cls: <class '__main__.c1'>
>>>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/04/23 23:05

    コメントありがとうございます!すみません、下記の違いがわからないのですが、呼び出し方にどんな違いがありますでしょうか?

    >>> ins1.f1()
    self: <__main__.c1 object at 0x7fa43f39e048>
    type(self): <class '__main__.c1'>
    self.__class__: <class '__main__.c1'>
    >>> ins1.f2()
    classmethod cls: <class '__main__.c1'>
    >>>

    キャンセル

  • 2021/04/25 14:04

    f2の方は「@classmethod」デコレータをメソッド定義箇所で付けているため、クラスメソッドオブジェクトとして処理されるため違いが生じます。

    以下のページなどを参照ください。
    - https://docs.python.org/ja/3/library/functions.html#classmethod
    - https://docs.python.org/ja/3/reference/datamodel.html#the-standard-type-hierarchy

    キャンセル

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

  • ただいまの回答率 87.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る