5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Pythonのクラス変数をインスタンス変数だと思ってて死んだ

Last updated at Posted at 2020-01-30

インスタンスを何度作り直しても __init__() で作ってるつもりの変数が変わらず、何ヶ月もハマってた

結論

python書き始めてからずーーっと勘違いしてました

class H:
  val = 1        <-------これは
  
  def __init__(self):
    self.val = 1        <-------これと同じものだと思ってました

本当はこうだった

class H:
  val = 1        <-------クラス変数
  
  def __init__(self):
    self.val = 1        <-------インスタンス変数

test code

import datetime, time

# クラス変数
class A:
    t = datetime.datetime.today()          #<-----------------# クラス変数: 何度インスタンスを作っても変わらない!!

class B:
    def __new__(cls):                      # <----------------# __new__ インスタンス変数
        self = object.__new__(cls)
        # print('__new__ :', str(id(self)))
        self.t = datetime.datetime.today()
        return self

class C:
    def __init__(self):                 # <----------------# __init__ インスタンス変数
        self.t = datetime.datetime.today()

class D:
    def __call__(self):                 # <----------------# __call__ インスタンス変数は class名() で呼ばれる。instance.__call__() を省力する感じ。
        return datetime.datetime.today()

def start():
    print("-start")
    print(datetime.datetime.today())

    print("-A")
    instance = A()
    print(A.t)           # class変数のみインスタンスではなく、クラス直で呼び出せる
    print(instance.t)    # インスタンスから取得        <----------- 違うインスタンスでも共通の値(一番最初にclassが呼ばれたときの数字で固定

    print("-B")
    instance = B()
    print(instance.t)

    print("-C")
    instance = C()
    print(instance.t)

    print("-D")
    instance = D()
    print(instance())    # <---------------- __call__ はclass名() で呼ばれる。instance.__call__() を省力する感じ。

##############################################################
if __name__ == "__main__":

    start()
    print("=========================================")
    time.sleep(1)
    start()

result

インスタンスを作り直しているのに、

-start
2020-01-30 14:29:24.227419
-A
2020-01-30 14:29:24.227217             <-----------ここと
2020-01-30 14:29:24.227217
-B
2020-01-30 14:29:24.227470
-C
2020-01-30 14:29:24.227494
-D
2020-01-30 14:29:24.227516
=========================================
-start
2020-01-30 14:29:25.230648
-A
2020-01-30 14:29:24.227217           <-----------ここが同じ orz
2020-01-30 14:29:24.227217
-B
2020-01-30 14:29:25.230766
-C
2020-01-30 14:29:25.230833
-D
2020-01-30 14:29:25.230877

他のは違う。class変数ってそういうやつやったんや・・・

全力で踏み抜くスタイル

クラス変数の使用上の注意
クラス変数にアクセスする場合は、特別な理由がない限り「インスタンス.クラス変数」や「self.クラス変数」のようにアクセスすることは避けるべきです。Python ではインスタンス変数をインスタンスオブジェクトから生成することができ、意図せずクラス変数をインスタンス変数で隠蔽してしまうことがあります。
https://uxmilk.jp/41600

色んな所で思いっきりやっております。ほえ〜。まいったまいった・・・。

まとめ

雰囲気でpythonするのはやめよう

5
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?