Pythonステップアップ_OOPオブジェクト向けプログラミング_インスタンスのプロパティとメソッド


目次
  • ディレクトリ
  • コンストラクタとデフォーマ
  • コンストラクタ_init__
  • 真のコンストラクタ_new__
  • デフォーマ_del__

  • インスタンスメソッド
  • Pythonにおける抽象的な方法
  • インスタンス属性
  • インスタンス属性
  • を表示
  • インスタンス属性とクラス属性の違い
  • 可変クラス属性
  • へのアクセス
  • 可変クラス属性
  • へのアクセス

    コンストラクタとデフォーマ
    コンストラクタ_init__()
    クラス関数__init__()はPythonクラスで予め定義された方法であり、再ロードされる必要がある.二重下線""冒頭と末尾に、Pythonでこのネーミング方式を用いる方法は特殊な方法と理解され、Pythonの特殊な方法は機能が非常に豊富で、種類も多く、変数名を宣言する際に特殊な方法と重複しないように注意しなければならない.
    通常、コンストラクタは、インスタンス化オブジェクトが作成された後、このインスタンスに戻るまでの間、特定のタスクまたは設定を実行するために使用されます.たとえば、インスタンスオブジェクトのプロパティ(selfキーで呼び出されたプロパティ)を初期化します.新しいオブジェクトをインスタンス化するときに自動的に呼び出されるため、インスタンスプロパティの初期化に加えて、いくつかの初歩的な診断コードを実行するためによく使用されます.呼び出しの具体的な手順:1.クラスのインスタンス化オブジェクト2を作成する.Python解析器はクラスがコンストラクタ3を実現したかどうかを検査する.ある場合、コンストラクタのインプリメンテーションが実行され、オブジェクトの作成が要求されると、対応する実パラメータが入力されます.インスタンスオブジェクトは、最初のパラメータselfに渡されます.4.ない場合は、インスタンス・オブジェクトに直接戻ります.
    一般に、コンストラクタで初期化が必要なインスタンス属性を設定することを推奨し、コンストラクタはreturn文がないNoneを返す必要があります.
    真・コンストラクタ_new__() __init__()と比較して__new__()が真のコンストラクタであり、実際には、Python解析器では__new__()を呼び出してインスタンスを生成し、そのインスタンスオブジェクトを__init__()に転送して初期化動作を実現する.しかし、__new__()は私たちがリロードする必要はめったにありません.一般的には、可変タイプのサブクラスを派生した後にリロードする必要があります.EG.派生String/Int/Tapleなどです.
    なぜ__new__()が真・コンストラクタなのか.この特殊なクラスメソッドは、__init__()がインスタンス化オブジェクトに渡されたのではなく、クラスのインスタンスオブジェクトを本当に返したからである.
    EXAMPLE:不可表型の派生
    class RoundFloat(float):
        def __new__(cls, val):
            return float.__new__(cls, round(val, 2)) #   __new__       ,               

    クラスRoundFloatはクラスfloatのサブクラスであり、親クラスの__new__()コンストラクタを再ロードすることで新しい可変タイプをカスタマイズします(Python 2.2以降はクラスとタイプを統一するので、Pythonの内蔵データ型を継承できます).RoundFloatのオブジェクトをインスタンス化すると、実際にはPython内蔵データ型Floatのオブジェクトがインスタンス化され、そのオブジェクトに対していくつかのカスタマイズされた操作が行われる(round(val,2)).NOTE:__init__()をリロードしてもこの結果は実現できますが、ここではできません.__new__()がリロードされていない場合でも、親Floatのコンストラクタがデフォルトで呼び出され、現在のRoundFloatタイプのオブジェクトではなくFloatタイプのオブジェクトが作成されます.これも両者の本質的な違いである.
    デフォーマ_del__()
    デフォーマ__del__()は、インスタンスオブジェクトがゴミ回収される前にPython解析器によって一度呼び出される(一度だけ呼び出され、その後インスタンスオブジェクトが回収される).デフォーマは、インスタンスオブジェクトがリソースを解放する前に特殊な処理機能を提供する方法です.一般的にはあまり使われませんが、デフォーマはオブジェクトの参照状態をチェックする良い方法であり、オブジェクトがまだ参照されている場合、デフォーマは実行されません.
    解構器を勝手にリロードしないように注意してください.
    インスタンスメソッド
    インスタンスメソッドの基本的な特徴は、インスタンスオブジェクトを実パラメータとして読み込むことです.Pythonから見れば,インスタンスメソッドは厳密にはクラス属性の1つであり,インスタンスメソッドはインスタンス化オブジェクトのみで呼び出すことができ,クラスで直接呼び出すことはできない.
    In [59]: class AClass(object):
        ...:     LOG = 'Define a class'
        ...:     def my_no_actioon_method(self):
        ...:         pass
        ...:
    
    In [60]: dir(AClass)
    Out[60]:
    ['LOG',
     '__class__',
     '__delattr__',
     '__dict__',
     '__doc__',
     '__format__',
     '__getattribute__',
     '__hash__',
     '__init__',
     '__module__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__',
     'my_no_actioon_method']     #    dir()                   。
    
    In [62]: AClass.my_no_actioon_method()
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    62-33bc36ae78f7> in ()
    ----> 1 AClass.my_no_actioon_method()
    
    TypeError: unbound method my_no_actioon_method() must be called with AClass instance as first argument (got nothing instead)

    クラスがインスタンスメソッドを直接呼び出すと、インスタンスメソッドがインスタンス化オブジェクトをバインドする必要があるため、TypeErrorがトリガーされます.これがselfの存在の意味です.selfキーワードを含むすべてのプロパティとメソッドは、クラスのインスタンス化オブジェクトによってのみ呼び出されます.したがって、一般的にクラスで定義されたインスタンスメソッドにはselfパラメータが含まれる必要があります.もちろん、この制約を他の方法で解除することもできます.これは後述します.
    In [63]: a_object = AClass()
    
    In [64]: a_object.my_no_actioon_method() #                       

    Pythonの「抽象的な方法」
    PythonはJavaの抽象的なメソッドをサポートしていませんが、親の``raise NotImplememtedErrorで同様の効果を実現できます.抽象メソッドの意味は、親メソッドと同じ名前のサブクラスメンバーメソッドを強制的に定義する必要があることです.
    In [74]: class AClass(object):
        ...:     LOG = 'Define a class'
        ...:     def my_method(self):
        ...:         raise NotImplementedError()
        ...:
        ...:
    
    In [75]: class BClass(AClass):
        ...:     pass
        ...:
    
    In [76]: b_object = BClass()
    
    In [77]: dir(b_object)
    Out[77]:
    ['LOG',
     '__class__',
     '__delattr__',
     '__dict__',
     '__doc__',
     '__format__',
     '__getattribute__',
     '__hash__',
     '__init__',
     '__module__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__',
     'my_method']
    
    In [78]: b_object.my_method()
    ---------------------------------------------------------------------------
    NotImplementedError                       Traceback (most recent call last)
    78-49e04830d861> in ()
    ----> 1 b_object.my_method()
    
    74-d6213dfecb1b> in my_method(self)
          2     LOG = 'Define a class'
          3     def my_method(self):
    ----> 4         raise NotImplementedError()
          5
          6
    
    NotImplementedError:

    だからこのようにして、プログラマーたちはおとなしくサブクラスでこの同名の方法を再ロードするしかなく、これはプログラムの規範に良い制約を与えた.
    In [79]: class BClass(AClass):
        ...:     def my_method(self):
        ...:         print "overload the function."
        ...:
        ...:
    
    In [80]: b_object = BClass()
    
    In [81]: b_object.my_method()
    overload the function.

    インスタンスのプロパティ
    クラス定義でselfキーワードで呼び出されるプロパティ、すなわちインスタンスオブジェクトに属するプロパティで、クラスオブジェクトは呼び出せません.クラス属性の作成は、実際には、インスタンスメソッド__setattr__を呼び出すことによって行われる.x.__setattr__('name', value) <==> x.name = value、それ以外に内蔵関数setattr()、setattr(object, name, value) <==> object.name = valuePythonは任意の時間にネーミングスペースを作成できるので、インスタンスオブジェクトを作成した後にインスタンス属性を定義したり、クラスを定義したときにインスタンス属性を作成したりすることができます.後者がインスタンス属性を作成する最も重要な方法は、コンストラクタ__init__()である.
    In [98]: class AClass(object):
        ...:     def __init__(self, name, age):
        ...:         self.name = name
        ...:         self.age = age
        ...:
    
    In [99]: a_object = AClass('JMILKFAN', 24)
    
    In [101]: a_object.name
    Out[101]: 'JMILKFAN'
    
    In [102]: a_object.age
    Out[102]: 24
    
    In [103]: a_object.sex = 'man'
    
    In [104]:  a_object.sex
    Out[104]: 'man'

    もちろん、コンストラクタでインスタンスプロパティを作成するほか、クラスの任意の場所で作成することもできます.これは推奨されていません.
    インスタンスのプロパティの表示
    インスタンス属性の表示は、クラス属性の表示と同様であり、dir()およびinstance.__dict__で表示できます.EXAMPLE:
    In [105]: dir(a_object)
    Out[105]:
    ['__class__',
     '__delattr__',
     '__dict__',
     '__doc__',
     '__format__',
     '__getattribute__',
     '__hash__',
     '__init__',
     '__module__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__',
     'age',
     'name',
     'sex']
    
    In [106]: a_object.__dict__
    Out[106]: {'age': 24, 'name': 'JMILKFAN', 'sex': 'man'}

    クラスのプロパティの表示と比較します.
    In [108]: dir(AClass)
    Out[108]:
    ['__class__',
     '__delattr__',
     '__dict__',
     '__doc__',
     '__format__',
     '__getattribute__',
     '__hash__',
     '__init__',
     '__module__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__']
    
    In [109]: AClass.__dict__
    Out[109]:
    dict_proxy({'__dict__': '__dict__' of 'AClass' objects>,
                '__doc__': None,
                '__init__': ,
                '__module__': '__main__',
                '__weakref__': '__weakref__' of 'AClass' objects>})

    NOTE:クラスまたは実力オブジェクトにとって__dict__は手動で修正できますが、この属性辞書を手動で修正することはお勧めしません.
    また、組み込みメソッドgetattr()またはインスタンスメソッド__getattribute__()によっても表示できます.
    In [119]: getattr(a_object, 'name')
    Out[119]: 'JMILKFAN'
    
    In [122]: a_object.__getattribute__('name')
    Out[122]: 'JMILKFAN'

    インスタンス属性とクラス属性の違い
    クラス属性はインスタンスに関係なく、インスタンスオブジェクトで可変クラス属性の値が明示的に変更されない限り、クラス属性の値はインスタンス化オブジェクトによって変更されません.クラス型の値は静的メンバーのように使用され、クラス属性attrは一般的にclass.attrで呼び出されます.また、インスタンスオブジェクトを使用してクラス属性instance.attrを呼び出すこともできますが、インスタンスオブジェクトに同名のインスタンス属性がない場合、instance.attrのattrはインスタンス属性であり、インスタンス属性の値を返します.逆に、インスタンスプロパティはクラスインスタンスオブジェクトのみで呼び出されます.
    クラス属性は静的属性に似ており、クラス属性を定義するときにメモリに静的空間を開き、保存します.また、この静的空間はクラスのすべてのインスタンスオブジェクトにアクセスできるため、クラス属性はクラスによってインスタンス化されたすべてのオブジェクトによって共有されます.
    In [150]: class AClass(object):
         ...:     version = 1.0
         ...:
    
    In [151]: a_object = AClass()
    
    In [152]: a_object.version
    Out[152]: 1.0
    
    In [153]: AClass.version += 1
    
    In [154]: a_object.version
    Out[154]: 2.0

    クラスプロパティの変更は、インスタンスオブジェクトによって感知されます.
    可変クラス属性へのアクセス
    可変クラス属性(int/str/tuple)では、インスタンスオブジェクトはクラス属性を変更できない価値があります.ただし、クラスプロパティが可変データ型の場合、インスタンスオブジェクトはその値を明示的に変更できます.
    In [124]: class AClass(object):
         ...:     version = 1.0
         ...:
    
    In [125]: a_object = AClass()
    
    In [126]: AClass.version
    Out[126]: 1.0
    
    In [127]: a_object.version
    Out[127]: 1.0
    
    In [128]: AClass.version = 1.1
    
    In [129]: a_object.version
    Out[129]: 1.1
    
    In [130]: AClass.version
    Out[130]: 1.1
    
    In [131]: a_object.version
    Out[131]: 1.1
    
    In [132]: b_object = AClass()
    
    In [133]: b_object.version
    Out[133]: 1.1
    
    In [134]: b_object.version = 1.2   #            ,             
    
    In [135]: AClass.version
    Out[135]: 1.1
    
    In [136]: a_object.version
    Out[136]: 1.1

    上記の例から、インスタンスオブジェクトはクラス属性(インスタンスオブジェクトに同名のインスタンス属性がない場合)を参照できますが、クラス属性を変更することはできません.新しいインスタンス属性を作成し、同名のクラス属性を上書きします.
    可変クラス属性へのアクセス
    In [143]: class AClass(object):
         ...:     aDict = {'name': 'jmilkfan'}
         ...:
    
    In [144]: a_object = AClass()
    
    In [146]: AClass.aDict
    Out[146]: {'name': 'jmilkfan'}
    
    In [147]: a_object.aDict
    Out[147]: {'name': 'jmilkfan'}
    
    In [148]: a_object.aDict['name'] = 'fanguiju'
    
    In [149]: AClass.aDict
    Out[149]: {'name': 'fanguiju'}

    インスタンス・オブジェクトがクラス・プロパティを変更できる本質は、インスタンス・オブジェクトが新しいインスタンス・プロパティを作成せずに変更されることです.
    注意:クラスプロパティをインスタンスオブジェクトで変更することは危険であり、潜在的なリスクが多いと考えられます.インスタンスオブジェクト名ではなく、クラス名を使用してクラス属性を変更することをお勧めします.