Pythonで名前つきリスト

[pukiwiki]
Python2.6以降には名前付きタプルってのが増えたらしいのですけれども個人的には、 名前付きリストを使いたい時も多いのでメモ。
[/pukiwiki]

つかいかたは、ほぼnamedlistと同じですが、内容を書き換えられます。
テスト環境は Py2.5 vistaですが、多分、2.6以降、他のOSでも動くかと。

長~~~いリストを扱っているとき、何番目が何の値だったか憶えられないから要素の名前でアクセスしたい。でも、プログラム上の理由でクラスに出来ない。 そんな時に よく使います。 sqliteのデータベースの戻り値とか。

名前付きタプルだと、データの数だけインスタンスを作らなきゃならないのが厭だったので名前付きリスト namedlistを書いてみました。

pickleとか shelveで独自のクラスを保存すると、たまに、よく判らないバグを作ってしまうことがあります。(私だけ?

保存時はリスト、 操作するときは名前付きリストに代入、ということもたまにやります。

>>> from namedlist import namedlist
>>> Pos3d=namedlist("Pos3d","x y z") #namedtuple と同じ
>>> p1=Pos3d( 0,1,2)
>>> p1
[0, 1, 2]
>>> p1.x, p1.y, p1.z #プロパティ名 x y zでアクセス
(0, 1, 2)
>>> p1.index(2) #これはlistの indexメソッド
2  # 値 2は、先頭要素をゼロ版目として、2番目の位置
     (日常での三番目)
>>> Pos3d.indexp("x") #プロパティ x の実際のリスト中での位置
0  # x は先頭    クラスメソッド indexp 
>>> p0=Pos3d( ) #値を省略して生成するとゼロに
>>> p0
[0, 0, 0]
>>> p1==[0,1,2]  #リストと名前付きリストの比較
True
>>> Pos3d(x=2,y=4,z=6 ) #キーワード引数での初期化
[2, 4, 6]
>>> p1[:]="abc"[:]  #スライスで代入
>>> p1
['a', 'b', 'c']
>>> p1[:]=[3,4,5][:] #namedlistインスタンスを使いまわしたい時
>>> p1
[3, 4, 5]
>>> type(p1)     
<class '__main__.Pos3d'>
>>> idx_z=Pos3d.indexp("z")
スライスして代入するのも時間が惜しい時、代入が使えない時に使用。

代入が使えない例

zlist=[ p[idx_z]  for p in p3list ]

namedlist.py として保存

"namedlist.py"
def namedlist(lname,lmemberstr):
    __m=lmemberstr.split()
    __ka="=0,".join(__m)+"=0"
    __a=",".join(__m)
    
    __idx=dict(zip(__m,range(len(__m))))
    __sep=[":",]*len(__m)
    class _(list):

        exec "def __new__(cls, %s):return list.__new__(cls,[%s])"%(__ka,__a)
        exec "def __init__(self, %s):list.__init__(self,[%s])"%(__ka,__a)
  
        def __get__(self,x):
            return self[__idx[x]]
        @classmethod
        def getp(cls,x,p):
            
            return x[cls.__idx[p]]
        @classmethod
        def indexp(cls,p):
            return cls.__idx[p]
            
        def __set__(self,x,v):
            self[__idx[x]]=v

    for m in __m :
        setattr(_,m,property(lambda self,p=m:self.__get__(p),
                             lambda self,v,p=m:self.__set__(p,v)))        

    _.__name__=lname

    return _


ここからデモコード。py2.5

from namedlist import namedlist  
if __name__=="__main__":
    """
    X=namedlist("X","a b c")
    x=X(1,2,3)
    print "x",x
    print "x.a",x.a
    print "x.b",x.b
    print "x.c",x.c
    print "x[0]",x[0]
    print "x[:]",x[:]
    x.a=100
    x.b*=100
    x[-1]=300
    print x
    """
    X=namedlist("X","a b c")
    x=X(1,2,3)
    print "x",x
    print "x.a",x.a
    print "x.b",x.b
    print "x.c",x.c
    print "x[0]",x[0]
    print "x[:]",x[:]
    x.a=100
    x.b*=100
    x[-1]=300
    print "x",x
    print "list(x)",list(x)
    print "x[:]=[1,2,3][:]"
    x[:]=[1,2,3][:]
    print "x",x
    print "x.a x.b x.c",x.a,x.b,x.c
    print "x.indexp('a'),x.indexp('b'),x.indexp('c') =0,1,2"
    print x.indexp('a'),x.indexp('b'),x.indexp('c')
   

コメントを残す

メールアドレスが公開されることはありません。