Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@uturned0

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

More than 1 year has passed since last update.

インスタンスを何度作り直しても __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するのはやめよう

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?