python仮想マシンにおけるクラスメカニズム

6851 ワード

本稿では、pythonのクラスメカニズムについて、pythonのクラスとオブジェクトの関係、クラスオブジェクトの作成方法、メタクラスの概念について説明し、クラスオブジェクトを作成するpythonコードのコンパイル後のバイトコードを分析し、バイトコードに基づいてクラスオブジェクトの作成/読み取りなどのメカニズムを分析します.
0クラス、すなわちオブジェクト
pythonでは、すべてオブジェクトです.もちろん、私たちが書いたクラスもオブジェクトです.
Class A(object):
     pass
instance_a = A()

上の3行のコードでは、pythonで実行するとclassオブジェクトとinstanceオブジェクトの2つのオブジェクトが作成されます.もちろん、ここにはobjectというオブジェクトもあります.彼はすでに存在するclassオブジェクトです.
クラスオブジェクト自体がインスタンスオブジェクトを作成する能力を持っています.これがクラスである理由です.
type関数を内蔵することで、オブジェクトタイプを表示できます.type(A)とtype(object)の結果は、type(a)の結果はmainである.A'>
とmain.A'>の違いは何ですか?特殊なclassオブジェクトであり、この特殊なclassオブジェクトは他のclassオブジェクトのtypeとなり、metaclassオブジェクトと呼ばれます.Metaclassオブジェクトがインスタンス化されるとClassオブジェクトになるのでClassAオブジェクトは数十instance_aオブジェクトのclassオブジェクトは、metaclassのinstanceオブジェクトでもあります.
1 classオブジェクトを作成する方法.
pythonコードでは、classキーワード(C++の宣言のような)でclassオブジェクトを作成し、このclassオブジェクトを作成することで、classオブジェクトからinstanceオブジェクトを作成できます.
classキーワードでclassオブジェクトを作成する以外に、python自体はtype()関数としてclassオブジェクトを作成する方法を提供しています.読者はtypeが前述したオブジェクトタイプを表示する関数ではないかと聞くかもしれません.type(inst)はinstタイプを返し、type関数にはtype(class_name, (base_class,),{'attr_name':class_attr})という別のフォーマットがあります.

type(  ,      (       ,    ),       (    ))



type関数を使用してclassオブジェクトを作成することは、classキーを直接使用することと等価です.

class Foo(object):
      bar = True

   :

Foo = type('Foo', (), {'bar':True})


では、Python仮想マシンではどのように作成されているのでしょうか.本稿ではpython仮想マシンC++コードについては説明しませんが、「pythonソース分析」および分析を参照すると、python仮想マシンがclassオブジェクトを作成するプロセスはtype関数を使用するのと同様で、ベースクラスリストを処理し、プロパティdictを入力し、これらの情報に基づいてclassオブジェクトを作成することがわかります.
pythonがclassオブジェクトを作成するときのバイトコードを分析し、pythonがclassオブジェクトを作成する具体的な手順を具体的に説明します.
3元クラス
まず、メタクラスについて、私は主にこの文章を参考にしました.http://blog.jobbole.com/21351/. ここでは、メタクラスの概念と使い方を簡単に紹介します.この文章を読むことで詳しく知ることができます.
メタクラスは何ですか.メタクラスはclassオブジェクトを作成するための「もの」であり、簡単に言えば、メタクラスはクラス(classオブジェクト)のクラスである.MyClass = type('MyClass', (), {})でクラスオブジェクトを作成できますが、関数typeはメタクラスです.メタクラスは必ずしもクラスではなく、関数であってもよいことに注意してください.
キーワード「metaclass」でクラスにメタクラスを指定できます.

class Foo(object):
    __metaclass__ = somethine


Fooクラスオブジェクトなどのclassオブジェクトを作成すると、まずmetaclassプロパティを表示し、metaでFooというクラスオブジェクトを作成します.見つからない場合は、組み込まれたメタクラス、すなわちtype()関数を使用して、このクラスオブジェクトを作成します.
では、元類は何ができるのでしょうか.メタクラスは、クラスが作成されたときに、カスタムでクラスを変更できます.たとえば、1つのクラスのすべての属性名を自動的に大文字に変更するには、メタクラスで実現できます.
例えば、私达のゲームの中で1つのメタクラスを使うシーンがあります:1つのプレイヤークラスPlayerClass、それは1つのプレイヤーのすべての机能を管理して、装备、物品、任务、属性、シーン、メールボックス、技能、友达...これらのコードを管理するために、1つの方法は、これらのコードを各モジュールごとに1つのクラスに作成してそれぞれ異なるファイルに置くことであり、PlayerClassのメタクラスはこれらを各ファイルに置くコードであり、PlayerClassに統合することで、コード構造をよりよく管理することができ、書くたびに他のモジュールの属性にアクセスしたいと考えています.selfを直接通過することができます.最後にPlayerClassに属しているため、attrがアクセスします.(もちろん、componentなど、他の方法でコードを整理することができます)
総じて、メタクラスが存在する目的は、クラスオブジェクトを作成するときに自動的に変更することです.
カスタムメタクラス
シーンを適用すると、メタクラスの作成方法について説明します.
#            ‘type’            
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    '''       ,          '''
    #        '__'     
    attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))

    #          
    uppercase_attr = dict((name.upper(), value) for name, value in attrs)

    #   'type'        
    return type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr  #                

class Foo(object):
    #            __metaclass__,            
    bar = 'bip'


あるいは、クラスによってメタクラスを記述します.
#    ,'type'       ,  'str' 'int'  
#   ,    type  
class UpperAttrMetaClass(type):
    # __new__   __init__          
    # __new__              
    #  __init__                
    #      __new__,              
    #   ,       ,          ,        __new__
    #        ,     __init__     
    #                __call__    ,        
    def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
        return type(future_class_name, future_class_parents, uppercase_attr)


メタ自体は簡単です
  • ブロッククラスの作成
  • 修正クラス
  • は、変更後のクラス
  • を返す.
    クラスメカニズムの実現
    実装リファレンス「pythonを使用してpython仮想マシンを実装」コードリファレンス:https://coding.net/u/shinepengwei/p/Byterun/git/blob/master/byterun_class.py
    次のコードを例にとります.
    class A(object):##      
       def __init__(self): 
           self.a_attr = 1
       def func(self,x):
           self.a_attr = x
    instance_a = A()
    
    

    このコードをコンパイルしたバイトコードは次のとおりです.
      2          0 LOAD_CONST               0 ('A')
                  3 LOAD_NAME                0 (object)
                  6 BUILD_TUPLE              1
                  9 LOAD_CONST               1 ()
                 12 MAKE_FUNCTION            0
                 15 CALL_FUNCTION            0
                 18 BUILD_CLASS         
                 19 STORE_NAME               1 (A)
    
     7          22 LOAD_NAME                1 (A)
                 25 CALL_FUNCTION            0
                 28 STORE_NAME               2 (instance_a)
                 31 LOAD_CONST               2 (None)
                 34 RETURN_VALUE        
    

    このレイヤのバイトコードは2つのことをしました:最初の行は、Aという名前のclssを作成します;6行目にinstanceという名前を作成します.aのオブジェクト、タイプはAです.
    前に説明したように、MyClass = type('MyClass', (), {})でクラスオブジェクトを作成できます.バイトコードから見ても同様であり、まず名前Aを(0)保存し、ベースクラスのtuple(3,6)を生成し、次にクラスに対応する属性と関数(9,12,15)を作成し、最後にクラスオブジェクト(18,19)を作成する.
    ここで、クラスに対応するプロパティと関数の作成に重点を置いて説明します.
    12にオフセットされたバイトコードは、次のように対応する関数を作成し、この関数を実行します.
      2           0 LOAD_NAME                0 (__name__)
                  3 STORE_NAME               1 (__module__)
    
      3           6 LOAD_CONST               0 ()
                  9 MAKE_FUNCTION            0
                 12 STORE_NAME               2 (__init__)
    
      5          15 LOAD_CONST               1 ()
                 18 MAKE_FUNCTION            0
                 21 STORE_NAME               3 (func)
                 24 LOAD_LOCALS         
                 25 RETURN_VALUE 
    
    

    これがクラスオブジェクトの属性dictを生成する関数バイトコードであり,このdictはクラスのname属性と2つのクラス関数を保存していることがわかる.
    LOAD_LOCALSは、次のようなdictを生成して戻ります.
    {
    '__module__': '__main__', 
    'func': <__main__.function object="" at="">, 
    '__init__': <__main__.function object="" at="">
    }