python:クラス属性とインスタンス属性、静的メソッド

16730 ワード

Class and Instance Attributes
クラス属性
  • クラスのインスタンスは、それぞれのインスタンス属性(Instance attributes)を有するため、通常、異なるインスタンスが持つインスタンス属性は異なる
  • である.
  • はまた、クラスレベルで属性を定義することもできます.クラス属性はこのクラスによって所有され、このクラスのすべてのインスタンスがこの属性を共有するため、すべてのインスタンスにとってこの値は同じです.
  • は、通常、クラス属性をすべてのメソッドの外に定義し、通常、一番上のクラスヘッダの右下に配置します.
  • #  
    class A:
        a = "I am a class attribute!"
    x = A()
    y = A()
    x.a
    'I am a class attribute!'
    
    y.a
    'I am a class attribute!'
    
    A.a
    'I am a class attribute!'
    
  • は、クラス名またはインスタンスを介してクラス属性
  • にアクセスできることを示す.
  • クラスのプロパティを変更するには、クラス名を使用する必要があります.属性名(ClassName.AttributeName)を変更します.そうでなければ、新しいインスタンス変数が作成されます.
  • class A:
        a = "I am a class attribute!"
    
    x = A()
    y = A()
    x.a = "This creates a new instance attribute for x!"
    y.a
    'I am a class attribute!'
    
    A.a
    'I am a class attribute!'
    
    A.a = "This is changing the class attribute 'a'!"
    A.a
    "This is changing the class attribute 'a'!"
    
    y.a
    "This is changing the class attribute 'a'!"
    
    # but x.a is still the previously created instance variable:
    x.a
    'This creates a new instance attribute for x!'
    
  • pythonのクラス属性とオブジェクト属性は、異なる辞書に格納されます.
  • x.__dict__
    {'a': 'This creates a new instance attribute for x!'}
    
    y.__dict__
    {}
    
    A.__dict__
    mappingproxy({'__dict__': ,
                  '__doc__': None,
                  '__module__': '__main__',
                  '__weakref__': ,
                  'a': "This is changing the class attribute 'a'!"})
    
    x.__class__.__dict__
    mappingproxy({'__dict__': ,
                  '__doc__': None,
                  '__module__': '__main__',
                  '__weakref__': ,
                  'a': "This is changing the class attribute 'a'!"})
    
  • 類の属性の例:機械人間.
  • クラス属性Threeを作成するLaws、これはtupleが3つの法則を含んでおり、この3つの法則はロボットのインスタンスごとに守らなければならない.

  • class Robot:
        Three_Laws = (
    """A robot may not injure a human being or, through inaction, allow a human being to come to harm.""",
    """A robot must obey the orders given to it by human beings, except where such orders would conflict with the First Law.,""",
    """A robot must protect its own existence as long as such protection does not conflict with the First or Second Law."""
    )
        def __init__(self, name, build_year):
            self.name = name
            self.build_year = build_year
    
        # other methods as usual
    
    for number, text in enumerate(Robot.Three_Laws):
        print(str(number+1) + ": 
    "
    + text)
    1: 
    A robot may not injure a human being or, through inaction, allow a human being to come to harm.
    2: 
    A robot must obey the orders given to it by human beings, except where such orders would conflict with the First Law.,
    3: 
    A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.
    
  • 以下の例:クラス属性でインスタンス数をカウントする
  • class C:
        counter = 0
        def __init__(self):
            type(self).counter += 1
        def __del__(self):
            # type(self)   C.counter     ,           (superclass)   
            type(self).counter -= 1
    
    if __name__ == "__main__":
        x = C()
        print("Number of instances: : " + str(C.counter))
        y = C()
        print("Number of instances: : " + str(C.counter))
        del x
        print("Number of instances: : " + str(C.counter))
        del y
        print("Number of instances: : " + str(C.counter))
    Number of instances: : 1
    Number of instances: : 2
    Number of instances: : 1
    Number of instances: : 0
    

    Static Methods
  • 以前はクラス属性を共有属性(public attributes)として使用していましたが、現在は以前のクラス属性をプライベート属性として使用し、前に二重下線を追加することができます.
  • は、その後、インスタンスメソッド(instance methods)を定義して、これらのプライベートクラス属性を取得および変更する.
  • class Robot:
        __counter = 0 
        def __init__(self):
            type(self).__counter += 1
    
        def RobotInstances(self):
            return Robot.__counter
    
    if __name__ == "__main__":
        x = Robot()
        print(x.RobotInstances())
        y = Robot()
        print(x.RobotInstances())
    
    1
    2
    
  • これは良いアイデアではありません.理由は2つあります.
  • 第一に、ロボットの数は単一のロボットインスタンスとは無関係である.
  • 第2に、インスタンスを作成する前にロボットの数を検索することはできません.
  • Robotという名前を呼ぼうとしたらRobotInstance()のメソッドでは、パラメータとしてインスタンスが必要であるため、エラーメッセージが表示されます.
  • Robot.RobotInstances()
    ---------------------------------------------------------------------------
    
    TypeError                                 Traceback (most recent call last)
    
     in ()
    ----> 1 Robot.RobotInstances()
    
    
    TypeError: RobotInstances() missing 1 required positional argument: 'self'
    
    #                 ,      “Self”:
    class Robot:
        __counter = 0
    
        def __init__(self):
            type(self).__counter += 1
    
        def RobotInstances():
            return Robot.__counter
    Robot.RobotInstances()
    0
    
    #             ,          :
    x = Robot()
    x.RobotInstances()
    ---------------------------------------------------------------------------
    
    TypeError                                 Traceback (most recent call last)
    
     in ()
          1 #             ,          :
          2 x = Robot()
    ----> 3 x.RobotInstances()
    
    
    TypeError: RobotInstances() takes 0 positional arguments but 1 was given
    
  • 呼び出しx.RobotInstance()はインスタンスメソッド呼び出しとみなされ、インスタンスメソッドはインスタンスを最初のパラメータとして参照する必要があります.
  • インスタンスへの参照を渡す必要がなく、クラス名またはインスタンス名で呼び出す方法が必要です.
  • ソリューションは、インスタンスへの参照を必要としない静的メソッド(static methods)から構成される.
  • メソッドを静的メソッドに変換するには、「@staticmethod」をメソッド名の上に付けるだけです.これは修飾器の構文です.
  • class Robot:
        __counter = 0
    
        def __init__(self):
            type(self).__counter += 1
    
        @staticmethod
        def RobotInstances():
            return Robot.__counter
    
    if __name__ == "__main__":
        print(Robot.RobotInstances())
        x = Robot()
        print(x.RobotInstances())
        y = Robot()
        print(x.RobotInstances())
        print(Robot.RobotInstances())
    
    0
    1
    2
    2
    
  • クラスの方法の例:これらの方法はいわゆる工場方法の定義で使用され、ここではこれらの方法について議論しない.
  • は、静的メソッドがある場合、他の静的メソッドを呼び出す必要がある場合によく使用されます.これを行うには、静的メソッドを使用する必要がある場合は、クラス名をハードコーディングする必要があります.これは、使用例でクラスを継承する場合に問題です.
  • #            ,q              (GCD)
    #                    (GCD),         。
    #         GCD              。
    #             (GCD)(         )               。
    #  ,8 24 GCD 8。
    #    “gcd”        “  ” “cls.gcd n1(N2)”   。“CLS”   “  ”。
    class fraction(object):
    
        def __init__(self, n, d):
            self.numerator, self.denominator = fraction.reduce(n, d)
    
    
        @staticmethod
        def gcd(a,b):
            while b != 0:
                a, b = b, a%b
            return a
    
        @classmethod
        def reduce(cls, n1, n2):
            g = cls.gcd(n1, n2)
            return (n1 // g, n2 // g)
    
        def __str__(self):
            return str(self.numerator)+'/'+str(self.denominator)
    x = fraction(8,24)
    print(x)
    1/3
    
    #   “about”         “Pets”。
    #       “Dogs” “Cats”   。  “about”     。
    #           “about”     “    ”,          :
    class Pets:
        name = "pet animals"
    
        @staticmethod
        def about():
            print("This class is about {}!".format(Pets.name))   
    
    
    class Dogs(Pets):
        name = "'man's best friends' (Frederick II)"
    
    class Cats(Pets):
        name = "cats"
    
    p = Pets()
    p.about()
    d = Dogs()
    d.about()
    c = Cats()
    c.about()
    
    This class is about pet animals!
    This class is about pet animals!
    This class is about pet animals!
    
    class Pets:
        name = "pet animals"
    
        @classmethod
        def about(cls):
            print("This class is about {}!".format(cls.name))
    
    class Dogs(Pets):
        name = "'man's best friends' (Frederick II)"
    
    class Cats(Pets):
        name = "cats"
    
    p = Pets()
    p.about()
    
    d = Dogs()
    d.about()
    
    c = Cats()
    c.about()
    This class is about pet animals!
    This class is about 'man's best friends' (Frederick II)!
    This class is about cats!
    
  • の欠点は、「about」メソッドがdogクラスまたはcatクラスのインスタンスによって呼び出されたことを知らないことです.
  • #                ,          :
    class Pets:
        name = "pet animals"
    
        @classmethod
        def about(cls):
            print("This class is about {}!".format(cls.name))
    
    class Dogs(Pets):
        name = "'man's best friends' (Frederick II)"
    
    class Cats(Pets):
        name = "cats"
    
    p = Pets()
    p.about()
    
    d = Dogs()
    d.about()
    
    c = Cats()
    c.about()
    This class is about pet animals!
    This class is about 'man's best friends' (Frederick II)!
    This class is about cats!
    

    参照先:https://www.python-course.eu/python3_class_and_instance_attributes.php