Python vs Modula-2

(1) Reading data file and data scaling

(1A) に進む  Workbench Python に戻る

<Task>

テキストファイル tab2.5.csv (内容はここ) の2行目以降にコンマ区切りで実験データ  (xi, yi, zi)が記入してあるから yiを読み込んでベクトル (y0,y1,・・・,yndata-1) を作りなさい。そしてベクトルの成分を a 倍(スケーリング)しなさい。 ただし、ファイルの読み込みは別モジュールとします。

<Excel を使えば>

このファイルをクリックすれば Excel が自動的に立ち上がると思います。2行目からは A, B, C列にデータが入っており、それがずーっと下まで続いています。 a の値は D1 セルに入っているものとします。スケーリング結果をD列に作りたければまず D2セルに「=B2*$D$1」を入力します。次に下方に drag すれば完了です。 この作業をPhthonとModula-2でやってみましょうというのが今回のテーマです。

<補足情報>

ベクトルの成分数 ndata はファイルを読んで判断しますが、一応1000以下とします(Python にとっては不要な情報です)。各行の成分数は3まで(A, B, C まで)とします。

<Python (Object Oriented Programming)>

[Module] fileRead.py

class readtest:
   
    def __init__(self,fname): 
        w = []
        file = open(fname, 'r')
        nline = 0
        while (True):
            line = file.readline()
            print(line, end="")
            if len(line)==0:
                break
            nline += 1
            if nline == 1:                
                self.header = line
            else:
                result = line.split(',')
                w.append(float(result[1]))  
        file.close()
        nline -= 1
        self.ndata = nline
        self.w = w
[Main] mytest.py
def scaling(x, a):
        n = len(x)
        out = x.copy() 
        for i in range(n):
            out[i] = a*out[i]
        return out

f = fileRead.readtest('tab2.5.csv')
ndata = f.ndata
y = f.w
yy = scaling(y, 2.)
print(y,', ',yy)
<Modula-2 (Structured Programming)>

DEFINITION MODULE fileRead.DEF

VAR header: ARRAY[0..79] OF CHAR;

PROCEDURE readtest(fname: ARRAY OF CHAR;
                   VAR ndata: INTEGER; 
                   VAR y: ARRAY OF LONGREAL);

IMPLEMENTATION MODULE fileRead.MOD

PROCEDURE readtest(fname: ARRAY OF CHAR;
  VAR ndata: INTEGER; VAR y: ARRAY OF LONGREAL);
VAR
  f : FIO.File;
  line, s: ARRAY[0..79] OF CHAR;
  nline,i: INTEGER;
  OK : BOOLEAN;
BEGIN
  IF NOT FIO.Exists(fname) THEN RETURN END;
  f := FIO.Open(fname);
  nline := 0; ndata := 0;
  LOOP
    FIO.RdStr(f,line);
    WrStr(line); WrLn;
    IF Str.Length(line)=0 THEN EXIT END;
    INC(nline);
    IF nline=1 THEN Str.Copy(header,line);
    ELSE
      Str.Item(s, line, Str.CHARSET{','}, 1);
	  y[ndata]:= Str.StrToReal(s,OK);
	  INC(ndata);
    END;
  END;
  FIO.Close(f);
END readtest;

[Main] mytest.MOD

IMPORT fileRead;
IMPORT WrStr, WrLn, WrLngReal, WrInt;

PROCEDURE scaling(VAR yout: ARRAY OF LONGREAL;
			yin: ARRAY OF LONGREAL;
			n: INTEGER;
			a: LONGREAL);
  VAR
    i: INTEGER;
  BEGIN
    FOR i:=0 TO n-1 DO
      yout[i]:= a*yin[i];
    END;
  END scaling;      	
  
VAR
  ndata: INTEGER;
  y,yy : ARRAY[0..999] OF LONGREAL;
  
BEGIN
  fileRead.readtest('tab2.5.csv', ndata, y);
  scaling(yy, y, ndata, 3.0);
  WrStr('ndata='); WrInt(ndata,1); WrLn;
  FOR i:=0 TO ndata-1 DO
    WrLngReal(y[i],5,10); WrStr(', '); 
	WrLngReal(yy[i],5,10); WrLn;
  END;
コメント
初心者がいうのもなんですが・・・
  • (time,conc,error) の全要素を得るには time = f.x 等とすると共にソースコードの手直しをする。
  • 少ない行数で実現できるということは、生産性が高いとみてよさそう。
  • class の中で attribute と method をどう設定するかで多彩な論理展開が可能になりそうである。
  • object は便利なアイデアであるが、油断は禁物。例えば上の out = x.copy() をout = x とすれば y の値が変わった。プログラムが走ればそれで安心とはいかない。
  • (time,conc,error) の全要素を得るには readtest の引数を増やすと共にソースコードの手直しをする。
  • 変数の受け渡し (value or address) が明確なので安心してプログラムが書ける。
  • 入出力も含め、すべてをモジュールから import せねばばらないのは確かに煩わしいが、グローバル変数のモジュールを最下層に持ってくる(exportだけのモジュールをを作る) など、階層構造をうまく作れば生産性が上げられるが、大きなプログラムでないとペイしないかもしれない。
  • ベクトルの要素数 ndata を明示せねばならないことが特に不便とは思えない。

11-9-2022, S. Hayashi