記事
· 2024年7月20日 24m read

ObjectScript/埋め込みPythonオブジェクトデータ解析ツール

埋め込みPythonは、同じプロセス空間で、IRIS言語とPython言語を組み合わせて使える面白い環境を提供しますが、組み合わせて使う場合、オブジェクトタイプとそのアクセス方法の違いをはっきり意識して使わないと混乱するように思います。その使い分けの勉強の為、両言語のオブジェクト参照から、その構造を解析ダンプするツールを作ってみました。とくに、実行中のPython情報が、ZWRITE Oref コマンドでの表示しかないようなので、有用かも知れません。ツールは、まだ、間違い、改良等があると思います(教えて下さい)が、ポストします。

ツール本体: Py.Dump.cls

Class Py.Dump Extends %RegisteredObject
{

/// Py.Dump.cls
/// ObjectScript 及び Python のオブジェクトデータ解析ツール(ダンパー)
/// 入力:ObjectScript 及び 埋め込みPython のデータオブジェクト参照 Oref
/// 出力: 端末と指定グローバル/ローカル変数(デフォルトは ^||o)に Oref のデータ構造を解析し出力する
///    変数には、データタイプの木構造がセットされる
/// 呼び出し:
/// >d ##Class(Py.Dump).o(oref)         出力グローバルは ^||o
/// >d ##Class(Py.Dump).o(oref,"...")   ... は出力グローバル/ローカル変数名(初期Killされる)
/// >d ##Class(Py.Dump).o(oref,"")     結果変数出力 zw @gbl は実行しない (^||o はセットされる)
/// or
/// 簡易エントリールーチン : Py.Dump.mac
/// >d o^Py.Dump(oref)
/// >d o^Py.Dump(oref,"")
/// >d o^py.Dump(oref,"o")
/// >d o^Py.Dump(oref,"^ABC")
/// >d o^Py.Dump({"a":2,"B":"漢字"},"")
///  
/// サンプル実行 : サンプルデータクラス Py.Sample.cls 利用
/// >d s^Py.Dump(i)  i=1,2...  i は Py.Sample.cls のクラスメソッド si
ClassMethod o(oref, gbl)
{
    If '$DATA(oref) Quit
    Set NoZwGbl=0
    If $DATA(gbl)#10=1,gbl="" {
        Set NoZwGbl=1 ; O(oref,"") の場合、^||o にセットするが、最後の zw @gbl なし
    }
    If $GET(gbl)="" {
        Set gbl= "^||o" ; デフォルト出力グローバル
    }
    If gbl'?.1"^".1"||"1(1"%",1A).AN Write !,"変数名 ",gbl," 指定エラー" Quit
    Kill @gbl
    Write !
    Do NextOref(oref,0,.gbl) 
    If 'NoZwGbl Write !!! ZWrite @gbl Write !
}

ClassMethod NextOref(oref, level = 0, gbl) [ Private ]
{
    If '$DATA(oref) Quit
    If '$DATA(%builtins) Set %builtins = ##class(%SYS.Python).Builtins()
    If '$DATA(%json) Set %json = %builtins.Import("json")
    If '$ISOBJECT(oref) {
        Set @gbl=oref
        Do ..NonObject(oref,gbl)
        Quit
    }
    Set classname=$CLASSNAME(oref)
    If classname="%SYS.Python"
    {
        Set type=..PythonType(oref)
        Set iterable=%builtins.hasattr(oref,"__iter__")
        If iterable {
            Set repr=%builtins.repr(oref)
            Write type,":",repr
            Set @gbl=type_":"_repr
            Set iskeys=%builtins.hasattr(oref,"keys")
            If iskeys {  ; key-value type
                /// dict
                Do ..Property(oref,level,gbl,type)        
                Do ..Method(oref,level,gbl,type)
                Set iter=oref."__iter__"()
                Set len=oref."__len__"()
                For i=0:1:len-1 {
                    Set key2=iter."__next__"()
                    Set oref2=oref."__getitem__"(key2)
                    Set type2=..PythonType(oref2) 
                    Write !?level*4,type,"(""",key2,""") = "
                    Set gbl2=$NAME(@gbl@(type,key2))                 
                    If $ISOBJECT(oref2) {
                        Do ..NextOref(oref2,level+1,gbl2)
                    }
                    Else {
                        Do ..NonObject(oref2,gbl2,type2)
                    }
                }
            }
            Else {
                /// tuple,list,set,range,bytearray
                Do ..Property(oref,level,gbl,type)
                Do ..Method(oref,level,gbl,type)
                Set iter=oref."__iter__"()
                Set len=oref."__len__"()
                Set @gbl@(type)=len          
                For i=0:1:len-1 {
                    Set oref2=iter."__next__"()
                    Set type2=..PythonType(oref2)
                    Write !?level*4,type,"(",i,") = "
                    Set gbl2=$NAME(@gbl@(type,i))              
                    If $ISOBJECT(oref2) {
                        Do ..NextOref(oref2,level+1,gbl2)
                    }
                    Else {
                        Do ..NonObject(oref2,gbl2,type2)
                    }
                }
            }
        }
        Else {
            Set repr=%builtins.repr(oref)
            Write type,":",repr
            Set @gbl@(type)=type_":"_repr
            Do ..Property(oref,level,gbl,type)
            Do ..Method(oref,level,gbl,type)       
        }
    }
    ElseIf classname="%Library.DynamicArray" {
        Set type="array"
        Try {
            Set json=oref.%ToJSON()
        }
        Catch e { 
            Set json="%ToJSON変換エラー:"_e.Name
        }
        Write type,":",json
        Set @gbl=type_":"_json
        Set size=oref.%Size()
        Set @gbl@(type)=size
        For i=0:1:size-1 {
            Write !?level*4,type,"(",i,") = "
            Set oref2=oref.%Get(i)
            Set type2=oref.%GetTypeOf(i)
            Set gbl2=$NAME(@gbl@(type,i))
            If $ISOBJECT(oref2) {
                Do ..NextOref(oref2,level+1,gbl2)
            }
            Else {
                Do ..NonObject(oref2,gbl2,type2)
            }
        }
    }
    ElseIf classname="%Library.DynamicObject" {
        Set type="object"
        Try {
            Set json=oref.%ToJSON()
        }
        Catch e { 
            Set json="%ToJSON変換エラー:"_e.Name
        }
        Write type,":",json
        Set @gbl=type_":"_json
        Set iter = oref.%GetIterator()
        While iter.%GetNext(.key2, .value2, .type2 ) {
            Write !?level*4,type,"(""",key2,""") = "
            Set gbl2=$NAME(@gbl@(type,key2))
            If $ISOBJECT(value2) {
                Do ..NextOref(value2,level+1,gbl2)
            }
            Else {
                Do ..NonObject(value2,gbl2,type2)
            }  
        }
    }
    Else {
        ; その他のクラス
        Write !?level*4,"Class : ",oref.%ClassName(1),!
        Do DumpObject^%apiOBJ(oref)
        ;w ! zw oref w !
    }
}

ClassMethod PythonType(oref)
{
    ;# Pythonのデータタイプを返す
    If '$DATA(%builtins) Set %builtins = ##class(%SYS.Python).Builtins()
    Quit %builtins.type(oref)."__name__"
}

ClassMethod NonObject(value, gbl, type = "") [ Private ]
{
    If value'="",$LISTVALID(value) {
        #; $list(...)
        Write "$list:",$LISTTOSTRING(value,,1)
        Set @gbl@("$list")=value
    }
    #; ObjectScript   number,string,boolean,null,unssingned
    #; Python         bool,date,datetime,float,int,str    
    Else {
        If $GET(type)="" Set type=$SELECT(value=+value:"numeric",1:"string")
        Write type,":",value 
        Set @gbl=type_":"_value
    }
}

ClassMethod Property(oref, level, gbl, type) [ Private ]
{
    Set properties=..GetProperties(oref)
    For i=0:1:properties."__len__"()-1 {
        Set prop=properties."__getitem__"(i)
        Set oref2=%builtins.getattr(oref,prop)
        Set type2=..PythonType(oref2)
        Write !?level*4,type," .",prop," = "
        Set gbl2=$NAME(@gbl@(type,"."_prop))
        If $ISOBJECT(oref2) {
            Set repr=%builtins.repr(oref2)
            Write type2,":",repr
            Set @gbl2@(type2)=repr
            #; datetime の場合、prop="max" で $isobject(oref2)=1 になり、
            #; do NextOref(oref2,level+1,gbl2)
            #; で、オブジェクト展開の再帰呼び出しをすると、なぜか同じ oref が現れ 
            #; __getattr__が再帰呼び出されて、再帰無限ループになる ?
            #; それで、Property値のネスト展開は NOP にする
            #; Property値は、Property名が分かれば、oref.Property名 で取れる
        }
        Else {
            Do ..NonObject(oref2,gbl2,type2)
        }
    }
}

ClassMethod Method(oref, level, gbl, type) [ Private ]
{
    Set methods=..GetMethods(oref)
    Set len=methods."__len__"()
    If len=0 Quit
    If 1 { ;# リスト表示
        Set repr=%builtins.repr(methods)
        Write !?level*4,"methods:",repr
        Set @gbl@(type,"methods")=repr
    }
    Else { ;# 展開表示
        For i=0:1:len-1 {
            Set method=methods."__getitem__"(i)
            Set oref2=%builtins.getattr(oref,method)
            Set type2=..PythonType(oref2)
            Write !?level*4,type," .",method,"() = "
            Set gbl2=$NAME(@gbl@(type,"."_method_"()"))
            Set repr=%builtins.repr(oref2)
            Write type2,":",repr
            Set @gbl2=type2_":"_repr
        }
    }
}

ClassMethod GetProperties(oref) [ Language = python ]
{
    properties = [ prop for prop in dir(oref) if not callable(getattr(oref, prop)) and not prop.startswith('__')]
    return properties
}

ClassMethod GetMethods(oref) [ Language = python ]
{
    methods = [method for method in dir(oref) if callable(getattr(oref, method)) and not method.startswith('__')]
    return methods
}

ClassMethod GetAttributes(oref) [ Language = python ]
{
    attributes = [attr for attr in dir(oref) if not attr.startswith('__')]
    return attributes
}

}

 

簡易・テストエントリー:Py.Dump.mac

ROUTINE Py.Dump
    #; Py.Dump    
    #; ObjectScript 及び Python のオブジェクトデータ解析ダンプ(Py.Dump.cls)簡易エントリー
    #; d o^Py.Dump(oref)           ^||o にセット
    #; d o^Py.Dump(oref,"^...")   グローバル変数 ^... にセット
    #; d o^Py.Dump(oref,"...")    ローカル変数 ... にセット
    #; d o^Py.Dump(oref,"")        ^||o にセットするが結果表示 zw ^||o はしない
o(oref,&gbl)    
    Do ##Class(Py.Dump).o(oref,.gbl)
    Quit
    #; サンプル実行
    #; d s^Py.Dump(i)        i=1,2...  Py.Sampleクラスの メソッド Si
    #; d s^Py.Dump(i,"")
    #; d s^Py.Dump(i,"^A")
    #; d s^Py.Dump(i,"o") 
s(i,gbl) ;
    Try {
        Set oref=$CLASSMETHOD("Py.Sample","s"_i)
        Do o(oref,.gbl)
    }
    Catch {
        Write !,$ZERROR
    }
    Quit
    ; d t^Py.Dump
t   ; 埋め込みPythonコード例(実験)
    Kill
    Set builtins = ##class(%SYS.Python).Builtins()
    Set json = builtins.Import("json")
    Set oref=builtins.dict()
    Do oref."__setitem__"("日本","富士山")  ; s oref.日本="富士山" は使えないので
    Do oref."__setitem__"("山",1122) ; 組み込み関数 __setitem__ の _ が結合演算子になるので使えないため、奇異だが "__...__" が必要
    Do oref.setdefault("川",567) 
    ZWrite oref ; zw oref だと変数に取れない
    Set d=builtins.repr(oref)
    Write !,"builtins.repr(oref)=",d  ;変数に取れるが表示形式
    ZWrite builtins.type(oref) ;zw だと Python type が正確に(変数に)取れない
    Set class=builtins.type(oref)."__class__"
    Set type=builtins.type(oref)."__name__"
    Write !,"class=",class,"  type=",type ;type取得
    ; zwrite oref の表示しか、Python情報を取れないのがとても不便 ! => ダンプツールが欲しい 
    Write !,"ダンプツール"
    Do o^Py.Dump(oref,"")
    ; zw oref では、%SYS.Pythonクラスであることぐらいしか情報が得られないが
    ; 以下の情報は、どの oref でも利用出来、有用です
    ZWrite builtins.dir(oref) ;これも Zw oref !! 
    ZWrite builtins.help(oref)
    ; zw を使わず、プログラムで情報を得るには...
    Set help=builtins.repr(builtins.dir(oref))
    Write !,help
    ; builtins.dir(oref) は Python listタイプ なので...
    Set list=builtins.dir(oref)
    Write !!,"Python list ループ",!
    Set iter=list."__iter__"() For i=0:1:list."__len__"()-1 Write:i'=0 " , " Write iter."__next__"()
    ; ObjectScriptの array に変換したほうが簡単か
    Set args={"ensure_ascii": 0},array = [].%FromJSON(json.dumps(list,args...))
    Write !,"ObjectScript Array ループ",!
    For i=0:1:array.%Size()-1 Write:i'=0 " , " Write array.%Get(i)
    ; oref の属性(Property,Method)を知りたい、変数に
    Write !,"Properties list = "
    Set Properties=##Class(Py.Dump).GetProperties(oref) ;Python listタイプ
    Do builtins.print(Properties)
    Write !,"Methods list = "
    Set Methods=##Class(Py.Dump).GetMethods(oref)
    Do builtins.print(Methods)
    Write !,"builtins oref ダンプ"
    Do o^Py.Dump(builtins,"")
    Write !,"json oref ダンプ"
    Do o^Py.Dump(json,"")
    ; 感想
    ; %SYS.Python クラスから派生したすべてのオブジェクト参照の処理は、Python言語に頭の切り替えが必要かと
    ; どこまで、ObjectScriptコード と Pythonコード を混在させて書くか? あるいは、Pyファイル経由や 
    ; ObjectScriptコード <-> Python 呼び出しでタイプ変換して、疎結合で組むか ?
    ; デバッグ、メンテ等を考えて要判断か...
    Quit

テストサンプル:Py.Sample.cls

Class Py.Sample Extends %RegisteredObject
{

/// Py.Sample.Cls
/// クラス   Py.Dump.cls のテストサンプル
/// ルーチン Py.Dump.mac で使う
ClassMethod s1() As %SYS.Python [ Language = python ]
{
    #; Pythonタイプ 
    from datetime import datetime, date
    sample_dict = {
        "整数": 42,
        "浮動小数点数": 3.14159,
        "文字列": "こんにちは、世界!",
        "リスト": [1, 2, "三"],
        "タプル": (7, "八", "九"),
        "辞書": {"キー1": "値1", "キー2": "値2"},
        "集合": {1, 2,frozenset(["一", "二"])},
        "ブール値": True,
        "None": None,
        "レンジ": range(0,2,20),
        "タプル":("山","川","谷"),
        "バイトアレイ": bytearray(b'example bytearray'),  # bytearray
        "バイト": b'example bytes',                       # bytes
        "日時": datetime.now(),
        "日付": date.today(),   
        '混合':[1, 2, 3,['四', '五',{'内部辞書1': '六','タプル':(8, 9, ('七', '八', {'さらに内部辞書': '九'}))}]]
        }
    return sample_dict
}

ClassMethod s2() As %DynamicAbstractObject
{
   ;# ObjectScritタイプ
	Set sample={
        "オブジェクト":{"A":33,"a":"lower case","漢字":"日本"},
        "アレイ":[1.23456789012345678901234,true,false,null,0,1,"","英語"],
        "混合":{"A":"一","B":["二","三",{"四":4,"五":5},"六"],"C":"八"}
        }
    Quit sample
}

ClassMethod s3() As %DynamicAbstractObject
{
    Set mix={ "Python dict":(..s1()) , "ObjectScript object":(..s2()) }
    Quit mix
}

ClassMethod s4() As %SYS.Python [ Language = python ]
{
    import iris
    mix= {"Python dict":iris.cls("Py.Sample").s1(), "ObjectScript object":iris.cls("Py.Sample").s2()}
    return mix
}

ClassMethod s5() As %SYS.Python [ Language = python ]
{
    return  (True,False,None)
}

ClassMethod s6() As %DynamicAbstractObject
{
    Set a=[] ;#ObjectScript の array
    Set a."0"=##class(%SYS.Python).True() ;#中は Python type
    Set a."1"=##class(%SYS.Python).False()
    Set a."2"=##class(%SYS.Python).None()
    Quit a
}

ClassMethod s7() As %SYS.Python [ Language = python ]
{
    import iris
    import json
    pydict = {'A':33,'a':'lower case','漢字':'日本'}
	#; ObjectScript型へ変換
    osdict = iris.cls("%DynamicObject")._New()._FromJSON(json.dumps( pydict , ensure_ascii=False ))
    mixed_dict = {"pydict":pydict, "osdict":osdict}
    return mixed_dict
}

ClassMethod s8() As %SYS.Python [ Language = python ]
{
    return  b'Hello Bytes!'
}

ClassMethod s9() As %DynamicAbstractObject
{
    Quit ##class(%SYS.Python).Bytes("Hello Bytes!")
}

ClassMethod s10() As %SYS.Python [ Language = python ]
{
    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def greet(self):
            return f"こんにちは、私の名前は {self.name} で、{self.age} 歳です。"
    person1 = Person("山田", 30)
    person2 = Person("上田", 25)
    print(person1.greet())
    print(person2.greet())
    return (person1, person2)
}

ClassMethod s11() As %SYS.Python [ Language = python ]
{
    class CustomCollection:
        def __init__(self, elements=None):
            if elements is None:
                elements = []
            self.elements = elements
        def __len__(self):
            return len(self.elements)
        def add(self, element):
            self.elements.append(element)
        def remove(self, element):
            if element in self.elements:
                self.elements.remove(element)
            else:
                raise ValueError(f"Element {element} not found in collection.")
        def find(self, element):
            return element in self.elements    
        def __str__(self):
            return f"CustomCollection with elements: {self.elements}"
    my_collection = CustomCollection([1, 2, 3, 4, 5])
    my_collection.add(6)
    print(my_collection)
    my_collection.remove(3)
    print(my_collection)
    print(my_collection.find(2))
    print(my_collection.find(3))
    print(len(my_collection))

    return my_collection
}

}

実行例 入力 oref は Py.Sample.cls の メソッド s1 と s10 の返り値 


USER>D s^Py.Dump(1)

dict:{'整数': 42, '浮動小数点数': 3.14159, '文字列': 'こんにちは、世界!', 'リスト': [1, 2, '三'], 'タプル': ('山', '川', '谷'), '辞書': {'キー1': '値1', 'キー2': '値2'}, '集合': {frozenset({'二', '一'}), 1, 2}, 'ブール値': True, 'None': None, 'レンジ': range(0, 2, 20), 'バイトアレイ': bytearray(b'example bytearray'), 'バイト': b'example bytes', '日時': datetime.datetime(2024, 7, 20, 9, 47, 50, 200660), '日付': datetime.date(2024, 7, 20), '混合': [1, 2, 3, ['四', '五', {'内部辞書1': '六', 'タプル': (8, 9, ('七', '八', {'さらに内部辞書': '九'}))}]]}
methods:['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
dict("整数") = int:42
dict("浮動小数点数") = float:3.141589999999999883
dict("文字列") = str:こんにちは、世界!
dict("リスト") = list:[1, 2, '三']
    methods:['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    list(0) = int:1
    list(1) = int:2
    list(2) = str:三
dict("タプル") = tuple:('山', '川', '谷')
    methods:['count', 'index']
    tuple(0) = str:山
    tuple(1) = str:川
    tuple(2) = str:谷
dict("辞書") = dict:{'キー1': '値1', 'キー2': '値2'}
    methods:['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
    dict("キー1") = str:値1
    dict("キー2") = str:値2
dict("集合") = set:{frozenset({'二', '一'}), 1, 2}
    methods:['add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']
    set(0) = frozenset:frozenset({'二', '一'})
        methods:['copy', 'difference', 'intersection', 'isdisjoint', 'issubset', 'issuperset', 'symmetric_difference', 'union']
        frozenset(0) = str:二
        frozenset(1) = str:一
    set(1) = int:1
    set(2) = int:2
dict("ブール値") = int:1
dict("None") = str:
dict("レンジ") = range:range(0, 2, 20)
    range .start = int:0
    range .step = int:20
    range .stop = int:2
    methods:['count', 'index']
    range(0) = int:0
dict("バイトアレイ") = bytearray:bytearray(b'example bytearray')
    methods:['append', 'capitalize', 'center', 'clear', 'copy', 'count', 'decode', 'endswith', 'expandtabs', 'extend', 'find', 'fromhex', 'hex', 'index', 'insert', 'isalnum', 'isalpha', 'isascii', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'pop', 'remove', 'removeprefix', 'removesuffix', 'replace', 'reverse', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    bytearray(0) = int:101
    bytearray(1) = int:120
    bytearray(2) = int:97
    bytearray(3) = int:109
    bytearray(4) = int:112
    bytearray(5) = int:108
    bytearray(6) = int:101
    bytearray(7) = int:32
    bytearray(8) = int:98
    bytearray(9) = int:121
    bytearray(10) = int:116
    bytearray(11) = int:101
    bytearray(12) = int:97
    bytearray(13) = int:114
    bytearray(14) = int:114
    bytearray(15) = int:97
    bytearray(16) = int:121
dict("バイト") = str:example bytes
dict("日時") = datetime:datetime.datetime(2024, 7, 20, 9, 47, 50, 200660)
    datetime .day = int:20
    datetime .fold = int:0
    datetime .hour = int:9
    datetime .max = datetime:datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)
    datetime .microsecond = int:200660
    datetime .min = datetime:datetime.datetime(1, 1, 1, 0, 0)
    datetime .minute = int:47
    datetime .month = int:7
    datetime .resolution = timedelta:datetime.timedelta(microseconds=1)
    datetime .second = int:50
    datetime .tzinfo = str:
    datetime .year = int:2024
    methods:['astimezone', 'combine', 'ctime', 'date', 'dst', 'fromisocalendar', 'fromisoformat', 'fromordinal', 'fromtimestamp', 'isocalendar', 'isoformat', 'isoweekday', 'now', 'replace', 'strftime', 'strptime', 'time', 'timestamp', 'timetuple', 'timetz', 'today', 'toordinal', 'tzname', 'utcfromtimestamp', 'utcnow', 'utcoffset', 'utctimetuple', 'weekday']
dict("日付") = date:datetime.date(2024, 7, 20)
    date .day = int:20
    date .max = date:datetime.date(9999, 12, 31)
    date .min = date:datetime.date(1, 1, 1)
    date .month = int:7
    date .resolution = timedelta:datetime.timedelta(days=1)
    date .year = int:2024
    methods:['ctime', 'fromisocalendar', 'fromisoformat', 'fromordinal', 'fromtimestamp', 'isocalendar', 'isoformat', 'isoweekday', 'replace', 'strftime', 'timetuple', 'today', 'toordinal', 'weekday']
dict("混合") = list:[1, 2, 3, ['四', '五', {'内部辞書1': '六', 'タプル': (8, 9, ('七', '八', {'さらに内部辞書': '九'}))}]]
    methods:['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    list(0) = int:1
    list(1) = int:2
    list(2) = int:3
    list(3) = list:['四', '五', {'内部辞書1': '六', 'タプル': (8, 9, ('七', '八', {'さらに内部辞書': '九'}))}]
        methods:['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
        list(0) = str:四
        list(1) = str:五
        list(2) = dict:{'内部辞書1': '六', 'タプル': (8, 9, ('七', '八', {'さらに内部辞書': '九'}))}
            methods:['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
            dict("内部辞書1") = str:六
            dict("タプル") = tuple:(8, 9, ('七', '八', {'さらに内部辞書': '九'}))
                methods:['count', 'index']
                tuple(0) = int:8
                tuple(1) = int:9
                tuple(2) = tuple:('七', '八', {'さらに内部辞書': '九'})
                    methods:['count', 'index']
                    tuple(0) = str:七
                    tuple(1) = str:八
                    tuple(2) = dict:{'さらに内部辞書': '九'}
                        methods:['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
                        dict("さらに内部辞書") = str:九


^||o="dict:{'整数': 42, '浮動小数点数': 3.14159, '文字列': 'こんにちは、世界!', 'リスト': [1, 2, '三'], 'タプル': ('山', '川', '谷'), '辞書': {'キー1': '値1', 'キー2': '値2'}, '集合': {frozenset({'二', '一'}), 1, 2}, 'ブール値': True, 'None': None, 'レンジ': range(0, 2, 20), 'バイトアレイ': bytearray(b'example bytearray'), 'バイト': b'example bytes', '日時': datetime.datetime(2024, 7, 20, 9, 47, 50, 200660), '日付': datetime.date(2024, 7, 20), '混合': [1, 2, 3, ['四', '五', {'内部辞書1': '六', 'タプル': (8, 9, ('七', '八', {'さらに内部辞書': '九'}))}]]}"
^||o("dict","None")="str:"
^||o("dict","methods")="['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']"
^||o("dict","タプル")="tuple:('山', '川', '谷')"
^||o("dict","タプル","tuple")=3
^||o("dict","タプル","tuple",0)="str:山"
^||o("dict","タプル","tuple",1)="str:川"
^||o("dict","タプル","tuple",2)="str:谷"
^||o("dict","タプル","tuple","methods")="['count', 'index']"
^||o("dict","バイト")="str:example bytes"
^||o("dict","バイトアレイ")="bytearray:bytearray(b'example bytearray')"
^||o("dict","バイトアレイ","bytearray")=17
^||o("dict","バイトアレイ","bytearray",0)="int:101"
^||o("dict","バイトアレイ","bytearray",1)="int:120"
^||o("dict","バイトアレイ","bytearray",2)="int:97"
^||o("dict","バイトアレイ","bytearray",3)="int:109"
^||o("dict","バイトアレイ","bytearray",4)="int:112"
^||o("dict","バイトアレイ","bytearray",5)="int:108"
^||o("dict","バイトアレイ","bytearray",6)="int:101"
^||o("dict","バイトアレイ","bytearray",7)="int:32"
^||o("dict","バイトアレイ","bytearray",8)="int:98"
^||o("dict","バイトアレイ","bytearray",9)="int:121"
^||o("dict","バイトアレイ","bytearray",10)="int:116"
^||o("dict","バイトアレイ","bytearray",11)="int:101"
^||o("dict","バイトアレイ","bytearray",12)="int:97"
^||o("dict","バイトアレイ","bytearray",13)="int:114"
^||o("dict","バイトアレイ","bytearray",14)="int:114"
^||o("dict","バイトアレイ","bytearray",15)="int:97"
^||o("dict","バイトアレイ","bytearray",16)="int:121"
^||o("dict","バイトアレイ","bytearray","methods")="['append', 'capitalize', 'center', 'clear', 'copy', 'count', 'decode', 'endswith', 'expandtabs', 'extend', 'find', 'fromhex', 'hex', 'index', 'insert', 'isalnum', 'isalpha', 'isascii', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'pop', 'remove', 'removeprefix', 'removesuffix', 'replace', 'reverse', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']"
^||o("dict","ブール値")="int:1"
^||o("dict","リスト")="list:[1, 2, '三']"
^||o("dict","リスト","list")=3
^||o("dict","リスト","list",0)="int:1"
^||o("dict","リスト","list",1)="int:2"
^||o("dict","リスト","list",2)="str:三"
^||o("dict","リスト","list","methods")="['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']"
^||o("dict","レンジ")="range:range(0, 2, 20)"
^||o("dict","レンジ","range")=1
^||o("dict","レンジ","range",0)="int:0"
^||o("dict","レンジ","range",".start")="int:0"
^||o("dict","レンジ","range",".step")="int:20"
^||o("dict","レンジ","range",".stop")="int:2"
^||o("dict","レンジ","range","methods")="['count', 'index']"
^||o("dict","整数")="int:42"
^||o("dict","文字列")="str:こんにちは、世界!"
^||o("dict","日付","date")="date:datetime.date(2024, 7, 20)"
^||o("dict","日付","date",".day")="int:20"
^||o("dict","日付","date",".max","date")="datetime.date(9999, 12, 31)"
^||o("dict","日付","date",".min","date")="datetime.date(1, 1, 1)"
^||o("dict","日付","date",".month")="int:7"
^||o("dict","日付","date",".resolution","timedelta")="datetime.timedelta(days=1)"
^||o("dict","日付","date",".year")="int:2024"
^||o("dict","日付","date","methods")="['ctime', 'fromisocalendar', 'fromisoformat', 'fromordinal', 'fromtimestamp', 'isocalendar', 'isoformat', 'isoweekday', 'replace', 'strftime', 'timetuple', 'today', 'toordinal', 'weekday']"
^||o("dict","日時","datetime")="datetime:datetime.datetime(2024, 7, 20, 9, 47, 50, 200660)"
^||o("dict","日時","datetime",".day")="int:20"
^||o("dict","日時","datetime",".fold")="int:0"
^||o("dict","日時","datetime",".hour")="int:9"
^||o("dict","日時","datetime",".max","datetime")="datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)"
^||o("dict","日時","datetime",".microsecond")="int:200660"
^||o("dict","日時","datetime",".min","datetime")="datetime.datetime(1, 1, 1, 0, 0)"
^||o("dict","日時","datetime",".minute")="int:47"
^||o("dict","日時","datetime",".month")="int:7"
^||o("dict","日時","datetime",".resolution","timedelta")="datetime.timedelta(microseconds=1)"
^||o("dict","日時","datetime",".second")="int:50"
^||o("dict","日時","datetime",".tzinfo")="str:"
^||o("dict","日時","datetime",".year")="int:2024"
^||o("dict","日時","datetime","methods")="['astimezone', 'combine', 'ctime', 'date', 'dst', 'fromisocalendar', 'fromisoformat', 'fromordinal', 'fromtimestamp', 'isocalendar', 'isoformat', 'isoweekday', 'now', 'replace', 'strftime', 'strptime', 'time', 'timestamp', 'timetuple', 'timetz', 'today', 'toordinal', 'tzname', 'utcfromtimestamp', 'utcnow', 'utcoffset', 'utctimetuple', 'weekday']"
^||o("dict","浮動小数点数")="float:3.141589999999999883"
^||o("dict","混合")="list:[1, 2, 3, ['四', '五', {'内部辞書1': '六', 'タプル': (8, 9, ('七', '八', {'さらに内部辞書': '九'}))}]]"
^||o("dict","混合","list")=4
^||o("dict","混合","list",0)="int:1"
^||o("dict","混合","list",1)="int:2"
^||o("dict","混合","list",2)="int:3"
^||o("dict","混合","list",3)="list:['四', '五', {'内部辞書1': '六', 'タプル': (8, 9, ('七', '八', {'さらに内部辞書': '九'}))}]"
^||o("dict","混合","list",3,"list")=3
^||o("dict","混合","list",3,"list",0)="str:四"
^||o("dict","混合","list",3,"list",1)="str:五"
^||o("dict","混合","list",3,"list",2)="dict:{'内部辞書1': '六', 'タプル': (8, 9, ('七', '八', {'さらに内部辞書': '九'}))}"
^||o("dict","混合","list",3,"list",2,"dict","methods")="['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']"
^||o("dict","混合","list",3,"list",2,"dict","タプル")="tuple:(8, 9, ('七', '八', {'さらに内部辞書': '九'}))"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple")=3
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",0)="int:8"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",1)="int:9"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",2)="tuple:('七', '八', {'さらに内部辞書': '九'})"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",2,"tuple")=3
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",2,"tuple",0)="str:七"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",2,"tuple",1)="str:八"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",2,"tuple",2)="dict:{'さらに内部辞書': '九'}"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",2,"tuple",2,"dict","methods")="['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",2,"tuple",2,"dict","さらに内部辞書")="str:九"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple",2,"tuple","methods")="['count', 'index']"
^||o("dict","混合","list",3,"list",2,"dict","タプル","tuple","methods")="['count', 'index']"
^||o("dict","混合","list",3,"list",2,"dict","内部辞書1")="str:六"
^||o("dict","混合","list",3,"list","methods")="['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']"
^||o("dict","混合","list","methods")="['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']"
^||o("dict","辞書")="dict:{'キー1': '値1', 'キー2': '値2'}"
^||o("dict","辞書","dict","methods")="['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']"
^||o("dict","辞書","dict","キー1")="str:値1"
^||o("dict","辞書","dict","キー2")="str:値2"
^||o("dict","集合")="set:{frozenset({'二', '一'}), 1, 2}"
^||o("dict","集合","set")=3
^||o("dict","集合","set",0)="frozenset:frozenset({'二', '一'})"
^||o("dict","集合","set",0,"frozenset")=2
^||o("dict","集合","set",0,"frozenset",0)="str:二"
^||o("dict","集合","set",0,"frozenset",1)="str:一"
^||o("dict","集合","set",0,"frozenset","methods")="['copy', 'difference', 'intersection', 'isdisjoint', 'issubset', 'issuperset', 'symmetric_difference', 'union']"
^||o("dict","集合","set",1)="int:1"
^||o("dict","集合","set",2)="int:2"
^||o("dict","集合","set","methods")="['add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']"
USER>

USER>d s^Py.Dump(10)
こんにちは、私の名前は 山田 で、30 歳です。
こんにちは、私の名前は 上田 で、25 歳です。

tuple:(<Py.Sample.Sample.s10.<locals>.Person object at 0x000001C78D128490>, <Py.Sample.Sample.s10.<locals>.Person object at 0x000001C78DCF0580>)
methods:['count', 'index']
tuple(0) = Person:<Py.Sample.Sample.s10.<locals>.Person object at 0x000001C78D128490>
    Person .age = int:30
    Person .name = str:山田
    methods:['greet']
tuple(1) = Person:<Py.Sample.Sample.s10.<locals>.Person object at 0x000001C78DCF0580>
    Person .age = int:25
    Person .name = str:上田
    methods:['greet']


^||o="tuple:(<Py.Sample.Sample.s10.<locals>.Person object at 0x000001C78D128490>, <Py.Sample.Sample.s10.<locals>.Person object at 0x000001C78DCF0580>)"
^||o("tuple")=2
^||o("tuple",0,"Person")="Person:<Py.Sample.Sample.s10.<locals>.Person object at 0x000001C78D128490>"
^||o("tuple",0,"Person",".age")="int:30"
^||o("tuple",0,"Person",".name")="str:山田"
^||o("tuple",0,"Person","methods")="['greet']"
^||o("tuple",1,"Person")="Person:<Py.Sample.Sample.s10.<locals>.Person object at 0x000001C78DCF0580>"
^||o("tuple",1,"Person",".age")="int:25"
^||o("tuple",1,"Person",".name")="str:上田"
^||o("tuple",1,"Person","methods")="['greet']"
^||o("tuple","methods")="['count', 'index']"
USER>
ディスカッション (1)1
続けるにはログインするか新規登録を行ってください