Python を使用したグローバル配列へのアクセス
Native SDK for Python はグローバル配列を操作するメカニズムを提供します。ここでは、以下の項目について説明します。
-
グローバル配列の概要 — グローバル配列の概念を示し、Native SDK がどのように使用されるかを簡単に説明します。
-
基本的なノード操作 — set()、get()、および kill() を使用して、グローバル配列内のノードの作成、ノードへのアクセス、およびノードの削除を行う方法を説明します。
-
nextSubscript() および isDefined() を使用した反復処理 — ObjectScript スタイルの反復処理をエミュレートするメソッドを紹介します。
この章の例では、iris.IRIS オブジェクトである irispy が既に存在し、サーバに接続されていると想定します。irispy は、以下のコードを使用して作成および接続されます。
import iris
conn = iris.connect('127.0.0.1', 51773, 'USER', '_SYSTEM', 'SYS')
irispy = iris.createIRIS(conn)
詳細は、iris パッケージの関数 connect() および createIRIS() のクイック・リファレンスのエントリを参照してください。
グローバル配列の概要
グローバル配列は、すべてのスパース配列のように、ツリー構造です (シーケンシャル・リストではありません)。グローバル配列の背後にある基本概念は、ファイル構造に例えて示すことができます。ツリーの各ディレクトリは、ルート・ディレクトリ識別子とそれに続く一連のサブディレクトリ識別子で構成されるパスによって一意に識別され、ディレクトリにはデータが含まれることも、含まれないこともあります。
グローバル配列の仕組みも同じです。ツリーの各ノードは、グローバル名識別子と一連の添え字識別子で構成されるノード・アドレスによって一意に識別され、ノードには値が含まれることも、含まれないこともあります。例えば、以下は 6 つのノードで構成されるグローバル配列で、そのうち 2 つのノードには値が含まれます。
root -->|--> foo --> SubFoo='A'
|--> bar --> lowbar --> UnderBar=123
値はその他のノード・アドレス (root または root->bar など) に格納できますが、それらのノード・アドレスが値なしの場合、リソースは無駄になりません。ディレクトリ構造とは異なり、グローバル配列内のすべてのノードに値または値を持つサブノードが必要です。InterSystems ObjectScript グローバルの表記では、値を持つ 2 つのノードは次のようになります。
root('foo','SubFoo')
root('bar','lowbar','UnderBar')
この表記では、グローバル名 (root) の後に、括弧で囲まれたコンマ区切り添え字リストが続きます。この両者で、ノードのノード・アドレス全体を指定します。
このグローバル配列は、Native SDK set() メソッドへの 2 つの呼び出しで作成されます。最初の引数が割り当てられる値で、それ以外の引数がノード・アドレスを指定します。
irispy.set('A', 'root', 'foo', 'SubFoo')
irispy.set(123, 'root', 'bar', 'lowbar', 'UnderBar')
グローバル配列 root は、最初の呼び出しが値 'A' をノード root('foo','SubFoo') に割り当てるまで存在しません。ノードは任意の順序で、任意の添え字セットを使用して作成できます。これら 2 つの呼び出しの順序を逆にした場合でも、同じグローバル配列が作成されます。値なしノードは自動的に作成され、不要になると自動的に削除されます。
この配列を作成する Native SDK コードを、以下に例示します。IRISConnection オブジェクトは、サーバへの接続を確立します。この接続は、irispy という名前の iris.IRIS のインスタンスによって使用されます。Native SDK メソッドを使用してグローバル配列を作成し、生成された永続値をデータベースから読み取った後、グローバル配列を削除します。
# Import the Native SDK module
import iris
# Open a connection to the server
args = {'hostname':'127.0.0.1', 'port':52773,
'namespace':'USER', 'username':'_SYSTEM', 'password':'SYS'
}
conn = iris.connect(**args)
# Create an iris object
irispy = iris.createIRIS(conn)
# Create a global array in the USER namespace on the server
irispy.set('A', 'root', 'foo', 'SubFoo')
irispy.set(123, 'root', 'bar', 'lowbar', 'UnderBar')
# Read the values from the database and print them
subfoo_value = irispy.get('root', 'foo', 'SubFoo')
underbar_value = irispy.get('root', 'bar', 'lowbar', 'UnderBar')
print('Created two values: ')
print(' root("foo","SubFoo")=', subfoo_value)
print(' root("bar","lowbar","UnderBar")=', underbar_value)
# Delete the global array and terminate
irispy.kill('root') # delete global array root
conn.close()
NativeDemo は、以下の行を出力します。
Created two values:
root('foo','SubFoo')="A"
root('bar','lowbar','UnderBar')=123
この例では、データベースへの接続と irispy (iris.IRIS のインスタンスで、接続オブジェクトを含む) の作成に、Native SDK iris パッケージのメソッドが使用されています。Native SDK メソッドは以下のアクションを実行します。
-
iris.connect() は、USER ネームスペースに関連付けられているデータベースに接続される、conn という名前の connection オブジェクトを作成します。
-
iris.createIRIS() は、サーバ接続 conn を介してデータベースにアクセスする、irispy という名前の iris.IRIS の新しいインスタンスを作成します。
-
iris.IRIS.set() は、データベース・ネームスペース USER に新しい永続ノードを作成します。
-
iris.IRIS.get() は、指定されたノードの値を返します。
-
iris.IRIS.kill() は、指定されたルート・ノードとそのサブノードすべてをデータベースから削除します。
-
iris.IRISConnection.close() は、接続を閉じます。
iris.IRIS のインスタンスの接続および作成の詳細は、“iris パッケージのメソッド” を参照してください。set()、get()、および kill() の詳細は、“基本的なノード操作” を参照してください。
この簡単な例には、反復処理といったより高度なトピックは含まれていません。複雑なグローバル配列の作成および反復処理の詳細は、“クラス iris.IRISGlobalNode” を参照してください。
グローバル配列の用語集
ここに示す概念の概要については、前のセクションを参照してください。この用語集の例は、以下に示すグローバル配列構造を指しています。Legs グローバル配列には、10 個のノードと 3 つのノード・レベルがあります。10 個のノードのうち 7 つには、値が含まれます。
Legs # root node, valueless, 3 child nodes
fish = 0 # level 1 node, value=0
mammal # level 1 node, valueless
human = 2 # level 2 node, value=2
dog = 4 # level 2 node, value=4
bug # level 1 node, valueless, 3 child nodes
insect = 6 # level 2 node, value=6
spider = 8 # level 2 node, value=8
millipede = Diplopoda # level 2 node, value="Diplopoda", 1 child node
centipede = 100 # level 3 node, value=100
指定された親ノードの直下にあるノードです。子ノードのアドレスは、親添え字リストの末尾に 1 つの添え字を追加して指定します。例えば、親ノード Legs('mammal') には子ノード Legs('mammal','human') および Legs('mammal','dog') があります。
ルート・ノードの識別子は、グローバル配列全体の名前でもあります。例えば、ルート・ノード識別子 Legs は、グローバル配列 Legs のグローバル名です。添え字とは異なり、グローバル名には文字、数字、およびピリオドのみを含めることができます ("グローバル命名規則" を参照)。
グローバル配列の要素で、グローバル名と任意の数の添え字識別子で構成されるネームスペースによって一意に識別されます。ノードは、値を含むか、子ノードを持つか、またはこれらの両方を持つ必要があります。
ノード・アドレス内の添え字の数。'レベル 2 ノード' は、'2 つの添え字を持つノード' のもう 1 つの表現方法です。例えば、Legs('mammal','dog') は、レベル 2 ノードです。ルート・ノード Legs の 2 レベル下で、Legs('mammal') の 1 レベル下です。
グローバル名とすべての添え字で構成される、ノードの完全なネームスペースです。例えば、ノード・アドレス Legs('fish') は、ルート・ノード識別子 Legs と 1 つの添え字 'fish' を含むリストで構成されます。コンテキストに応じて、Legs (添え字リストなし) はルート・ノード・アドレスまたはグローバル配列全体を参照することができます。
グローバル配列ツリーの基点にある添え字なしノードです。ルート・ノードの識別子は、その添え字なしのグローバル名です。
特定のノードのすべての下位ノードは、そのノードのサブノードと呼ばれます。例えば、ノード Legs('bug') には 2 つのレベルの 4 つの異なるサブノードがあります。9 つの添え字付きノードはすべて、ルート・ノード Legs のサブノードです。
ルート・ノードの下にあるノードはすべて、グローバル名および 1 つまたは複数の添え字識別子のリストを指定して処理されます(グローバル名に添え字リストを加えたものが、ノード・アドレスです)。添え字は、bool、bytes、bytearray、Decimal、float、int、str のいずれかです。
多くの Native SDK メソッドは有効なノード・アドレスを指定する必要がありますが、ノード・アドレスは必ずしも既存のノードを指す必要はありません。例えば、set() メソッドは value 引数とターゲット・アドレスを取り、そのアドレスに値を格納します。ターゲット・アドレスにノードが存在しない場合は、新しいノードが作成されます。
ノードに含めることができる値のタイプは、bool、bytes、bytearray、Decimal、float、int、str、IRISList、または None です ("型キャスト・メソッドおよびサポートされるデータ型" を参照)。子ノードを持つノードは値なしにできますが、子ノードのないノードには値を含める必要があります。
ノードは、データを含むか、子ノードを持つか、またはこれらの両方を持つ必要があります。子ノードを持っているがデータを含まないノードは、値なしノードと呼ばれます。値なしノードは、下位レベルのノードへのポインタとしてのみ存在します。
グローバル命名規則
グローバル名と添え字は、次の規則に従います。
-
ノード・アドレスの長さ (グローバル名とすべての添え字の長さの合計) は最大 511 文字です(入力した一部の文字は、この制限のために、複数のエンコードされた文字としてカウントされることがあります。詳細は、“グローバル参照の最大長” を参照してください)。
-
グローバル名には文字、数字、およびピリオド ('.') を使用でき、最大 31 文字の有効文字を使用できます。文字で始まる必要があり、ピリオドで終了することはできません。
-
添え字は、bool、bytes、bytearray、Decimal、float、int、str のいずれかです。文字列の添え字では大文字と小文字が区別され、あらゆる文字 (出力不能文字を含む) を使用できます。添え字の長さは、ノード・アドレスの最大長によってのみ制限されます。
基本的なノード操作
ここでは、set() メソッド、get() メソッド、および kill() メソッドを使用して、ノードの作成、ノードへのアクセス、およびノードの削除を行う方法について説明します。これらのメソッドには、以下のシグニチャがあります。
set (value, globalName, subscripts)
get (globalName, subscripts)
kill (globalName, subscripts)
-
value は、bool、bytes、bytearray、Decimal、float、int、str、IRISList、None のいずれかです。
-
globalName には、文字、数字、およびピリオド (".") のみを含めることができます。文字で始まる必要があり、ピリオドで終了することはできません。
-
subscripts は、bool、bytes、bytearray、Decimal、float、int、str のいずれかです。文字列の添え字では大文字と小文字が区別され、出力不能文字を含めることができます。
このセクションのすべての例で、irispy という名前の IRIS の接続済みインスタンスが既に存在すると想定しています (“Python での接続の作成” を参照)。
iris.IRIS.set() は、value 引数、globalname 引数、および *subscripts 引数を取り、指定されたノード・アドレスにその値を格納します。そのアドレスにノードが存在しない場合は、新しいノードが作成されます。
以下の例では、set() の最初の呼び出しによって、新しいノードがサブノード・アドレス myGlobal('A') に作成され、このノードの値が文字列 'first' に設定されます。2 回目の呼び出しによって、サブノードの値が変更され、整数 1 に置き換えられます。
irispy.set('first','myGlobal','A') # create node myGlobal('A') = 'first'
irispy.set(1,'myGlobal','A') # change value of myGlobal('A') to 1.
iris.IRIS.get() は、globalname 引数および *subscripts 引数を取り、指定されたノード・アドレスに格納されている値を返すか、そのアドレスに値が存在しない場合は None を返します。
irispy.set(23,'myGlobal','A')
value_of_A = irispy.get('myGlobal','A')
get() メソッドは、決まった形式のない値を返します。特定のデータ型を返すには、いずれかの IRIS.get() 型キャスト・メソッドを使用します。使用可能なメソッドは、getBoolean()、getBytes()、getDecimal()、getFloat()、getInteger()、getString()、getIRISList()、および getObject() です。
iris.IRIS.kill() — 指定したノードとそのサブノードすべてを削除します。ルート・ノードが削除された場合、または値を持つすべてのノードが削除された場合、グローバル配列全体が削除されます。
グローバル配列 myGlobal には、最初に以下のノードが含まれます。
myGlobal = <valueless node>
myGlobal('A') = 0
myGlobal('A',1) = 0
myGlobal('A',2) = 0
myGlobal('B') = <valueless node>
myGlobal('B',1) = 0
この例では、その 2 つのサブノードで kill() を呼び出すことで、グローバル配列を削除します。最初の呼び出しによって、ノード myGlobal('A') とその両方のサブノードが削除されます。
irispy.kill('myGlobal','A') # also kills myGlobal('A',1) and myGlobal('A',2)
2 番目の呼び出しによって、値を持つ最後のサブノードが削除され、グローバル配列全体が削除されます。
irispy.kill('myGlobal','B',1) # deletes last value in global array myGlobal
-
親ノード myGlobal('B') は、値がなく、サブノードもなくなったため、削除されます。
-
ルート・ノード myGlobal は値がなく、サブノードもなくなったため、グローバル配列全体がデータベースから削除されます。
nextSubscript() および isDefined() を使用した反復処理
ObjectScript での標準の反復処理メソッドは $ORDER および $DATA です。Native SDK には、これらの ObjectScript メソッドをエミュレートするユーザ向けに、対応するメソッド nextSubscript() および isDefined() が用意されています。
IRIS.nextSubscript() メソッド ($ORDER に対応) は、反復処理メソッドとしては node() ほど強力ではありませんが、ほぼ同じように機能し、同一の親の下の一連のノードを反復処理します。ノード・アドレスと反復処理の方向が指定されると、このメソッドは、指定されたノードと同じ親の次のノードの添え字を返すか、指定された方向にこれ以上ノードがない場合は None を返します。
IRIS.isDefined() メソッド ($DATA に対応) は、指定されたノードに値、サブノード、またはその両方があるかどうかの確認に使用できます。以下の値を返します。
-
0 — 指定したノードは存在しません。
-
1 — ノードは存在し、値があります。
-
10 — ノードに値はありませんが、子ノードがあります。
-
11 — ノードには値と子ノードの両方があります。
返り値を使用して、いくつかの有用なブーリアン値を確認できます。
exists = (irispy.isDefined(root,subscripts) > 0)
hasValue = (irispy.isDefined(root,subscripts) in [1,11]) # [value, value+child]
hasChild = (irispy.isDefined(root,subscripts) in [10,11]) # [child, value+child]
以下のコードでは、nextSubscript() を使用して、heroes('dogs') のノードに対し、heroes('dogs',chr(0)) (考えられる最初の添え字) から開始して反復処理が行われます。各ノードを isDefined() でテストして、子があるかどうか確認します。
direction = 0 # direction of iteration (boolean forward/reverse)
next_sub = chr(0) # start at first possible subscript
while next_sub != None:
if (irispy.isDefined('heroes','dogs',next_sub) in [10,11]): # [child, value+child]
print(' ', next_sub, 'has children')
next_sub = irispy.nextSubscript(direction,'heroes','dogs',next_sub)
print('next subscript = ' + str(next_sub) )
出力:
next subscript = Balto
next subscript = Hachiko
next subscript = Lassie
Lassie has children
next subscript = Whitefang
next subscript = None