静岡理工科大学 菅沼ホーム 目次 索引

入出力と文

  1. 入出力

    1. 標準入出力

        コマンドプロンプト上でデータを変数に入力するためには(標準入力sys.stdin からの入力),組み込み関数 input を使用します.引数を記述すると,それが末尾の改行を除いて標準出力に書き出され,入力された 1 行を読み込み,文字列に変換して返します(末尾の改行を除去).また,変数の値などを標準出力sys.stdout )に表示するためには,組み込み関数 print を使用します.print は,与えられたオブジェクトを,スペースで区切り,標準出力に表示し,最後に改行します.
      01	>>> a = input("data? ")
      02	data? 10 3.141592654 abc
      03	>>> b = a.split()
      04	>>> b
      05	['10', '3.141592654', 'abc']
      06	>>> x = int(b[0])
      07	>>> y = float(b[1])
      08	>>> z = b[2]
      09	>>> print(x, y, z)
      10	10 3.141592654 abc
      11	>>> str = "x = {0:3d}, y = {1:.2f}, z = {2:s}".format(x, y, z)
      12	>>> print(str)
      13	x =  10, y = 3.14, z = abc
      				
      01,02 行目

        01 行目のコマンドによって,02 行目のように,画面上に「 data? 」というメッセージが出力されます.「 10 3.141592654 abc 」を入力し改行を行うと,入力した結果が文字列として変数 a に代入されます.

      03 行目~ 05 行目

        入力された文字列には,3 つのデータが含まれていますので,文字列型に対するメソッド split を使用して分離します.分離されたデータは,リストとして返されます.リストは,C/C++ の配列などと似たデータ構造であり,複数のデータを取り扱うことができます.06 行目~ 08 行目に示すように,リスト内の i 番目のデータを添え字 [i-1] で参照することができます.

      06 行目~ 08 行目

        数値データは,文字列のままでは演算等に使用できませんので,組み込み関数 intfloat を使用して,整数や浮動小数点数に変換します.

      09,10 行目

        組み込み関数 print を使用して,3 つの変数の値を出力しています.

      11 行目~ 13 行目

        データを書式化して出力したい場合は,文字列型に対するメソッド format を使用します.format は,C/C++ の printf に似た方法によって書式化を実行します.この例では,整数は 3 桁で,また,浮動小数点数は小数点以下 2 桁で出力します.

      C++ の場合

        以下に示す例においては,データを 1 つずつ,対応する型に変換しながら読み込んでいますが( scanf ),1 行ずつ文字列として読み込むことも可能です.その際は,Python のように,データを分離・変換する必要があります.
      int x;
      double y;
      char z[10];
      printf("data? ");
      scanf("%d %lf %s", &x, &y, z);   // 10 3.141592654 abc を入力
      printf("%d %f %s\n", x, y, z);   // 10 3.141593 abc を出力
      printf("%3d %.2f %s\n", x, y, z);   //  10 3.14 abc を出力
      				
        以下に示す内容のスクリプトファイルを実行すると,キーボードから入力されたデータを "end\n" が入力されるまで,画面に表示続けます.
      # -*- coding: UTF-8 -*-
      import sys
      for line in sys.stdin :
      	if line == "end\n" :
      		break
      	else :
      		print(line)
      			# 以下の文とほぼ同じ
      line = ""
      while line != "end\n" :
      	print(line)
      	line = sys.stdin.readline()
      				

    2. ファイル入出力

        ここでは,ファイル入出力の際必要となる基本的な関数やメソッドについて説明します.

      • open('file_name', 'w')ファイルオブジェクト f を返す.通常,2 つの引数を伴って呼び出される.最初の引数はファイル名の入った文字列である.2 つ目の引数,mode 引数も文字列であり,ファイルをどのように使用するかを示す数個の文字が入っている.ファイルが読み出し専用なら 'r',書き込み専用なら 'w' とする.'a' はファイルを追記用に開き,ファイルに書き込まれた内容は自動的にファイルの終端に追加される.'r+' はファイルを読み書き両用に開く.mode 引数を省略すると,'r' であると見なされる.通常,ファイルはテキストモードで開かれるが,JPEG ファイルや EXE ファイルのようなバイナリデータの場合は,mode に 'b' を付け,バイナリモードで開く必要がある.

      • f.close() : ファイルオブジェクト f を閉じる.

      • f.closed : ファイルオブジェクト f が閉じられていれば True に設定される.

      • f.read([size]) : 最大 size バイトのデータを読み出し,文字列(テキストモードの場合),または,bytes オブジェクト(バイナリーモードの場合)として返す.size が省略されたり負の数であった場合,ファイルの内容全てを読み出して返す.また,ファイルの終端に達していた場合,空の文字列( '' )を返す.

      • f.readline() : ファイルから 1 行だけ読み取る.なお,改行文字( \n )は読み出された文字列の終端に残る.

      • f.write(object) : object の内容をファイルに書き込み,書き込まれた文字数を返す.オブジェクトの型は,書き込む前に,文字列(テキストモード),または,bytes オブジェクト(バイナリーモード)に変換しなければならない.

      • f.seek(offset[, from_what]) : ファイルオブジェクトの位置を変更する.位置は from_what によって指定された値に offset を加えて計算される.from_what の値が 0 ならばファイルの 先頭から,1 ならば現在のファイル位置,2 ならばファイルの終端を基準点とする.from_what のデフォルトは 0 である.

        以下に示すのは,上で述べた関数やメソッドの簡単な使用例です.
      >>> f = open("test.txt", "w")   # 出力のためにオープン
      >>> f.write("10 3.1492654 abc\n菅沼義昇\n")
      22
      >>> f.close()
      >>> f = open("test.txt", "r")   # 入力のためにオープン
      >>> f.read()
      '10 3.1492654 abc\n菅沼義昇\n'
      >>> f.seek(0)   # ファイルの先頭に移動
      0
      >>> f.readline()
      '10 3.1492654 abc\n'
      >>> f.readline()
      '菅沼義昇\n'
      >>> f.readline()
      ''   # ファイルの終わりを示す
      >>> f.close()
      				
        ファイルの内容すべてを読み込むため,次の例のように,標準関数 iter を使用した方法がしばしば使用されます.
      >>> with open('test.txt') as fp:
      ...     for line in iter(fp.readline, ''):
      ...             print(line,end="")
      ...
      10 3.1492654 abc
      菅沼義昇
      				
        数値データを要素と持つリスト(配列)を扱いたい場合,拡張モジュール NumPy がインストールされていると,以下に示すように,配列に対する入出力を簡単に行うことができます.
      >>> import numpy as np
      >>> a = np.array([[1, 2, 3], [4, 5, 6]])   # 2 行 3 列
      >>> np.savetxt('test.txt', a)   # 配列 a の出力
      >>> b = np.loadtxt('test.txt')   # 配列 b への入力
      >>> b
      array([[ 1.,  2.,  3.],
             [ 4.,  5.,  6.]])
      				

      C++ の場合

      double a[2][3] = {{1, 2, 3}, {4, 5, 6}}, b[2][3];
      FILE *out = fopen("test.txt", "w");   // 配列 a の出力
      for (int i1 = 0; i1 < 2; i1++) {
      	for (int i2 = 0; i2 < 3; i2++)
      		fprintf(out, " %f", a[i1][i2]);
      	fprintf(out, "\n");
      }
      fclose(out);
      FILE *in = fopen("test.txt", "r");   // 配列 b への入力
      for (int i1 = 0; i1 < 2; i1++)
      	for (int i2 = 0; i2 < 3; i2++)
      		fscanf(in, "%lf", &b[i1][i2]);
      fclose(in);
      for (int i1 = 0; i1 < 2; i1++) {   // 結果の表示
      	for (int i2 = 0; i2 < 3; i2++)
      		printf(" %f", b[i1][i2]);
      	printf("\n");
      }
      				

  2. 単純文

    1. 代入文

        代入は,基本的に C/C++ と同じような形で行いますが,複数同時の代入multiple assignment )が可能な点が大きく異なっています(このような機能,必要?).例えば,以下に示す代入文によって,変数 x には 10,変数 y には 12 が代入されます.プログラムを読みにくくする原因ともなりかねません.特別な場合を除き,使用しない方が良いと思います.
      >>> x, y = 10, 3 * 4
      >>> print(x, y)
      10 12
      				
        Python のほとんどのデータは,クラスのオブジェクトです.変数が示す場所(アドレス)にデータ自身が記憶されているわけではなく,変数はデータ(オブジェクト)が記憶されている場所への参照(場所のアドレス)を表しています.代入においては,データをコピー(新しく生成)してそのデータに対する参照を代入しているのか,または,データそのものはすでに存在するものを使用し,そのデータに対する参照を代入しているのかといった違いに注意する必要があります.既に第 3 章において多少説明しましたが,重要なことですので,再度説明しておきます.まず最初は,整数や浮動小数点数などの基本的なデータに関する説明です.
      		# 整数の場合,文字列の場合も同じ
      01	>>> a = 10
      02	>>> b = 10
      03	>>> a == b, a is b
      04	(True, True)
      05	>>> b = a
      06	>>> a == b, a is b
      07	(True, True)
      08	>>> b = 20
      09	>>> a == b, a is b
      10	(False, False)
      11	>>> a, b
      12	(10, 20)
      		# 浮動小数点数の場合,虚数(複素数)の場合も同じ
      13	>>> c = 1.2
      14	>>> d = 1.2
      15	>>> c == d, c is d
      16	(True, False)
      17	>>> d = c
      18	>>> c == d, c is d
      19	(True, True)
      20	>>> d = 1.3
      21	>>> c == d, c is d
      22	(False, False)
      23	>>> c, d
      24	(1.2, 1.3)
      				
        代入とは,= 記号の右辺で得られた結果を左辺で指定した変数が示す領域に記憶することです.01,02 行目においては,整数リテラル 10 が変数 a,b が示す領域に記憶されます.03,04 行目を見ると,値の比較においても,オブジェクトの比較においても,両者は等しくなっています.このことは,整数リテラル 10 が記憶領域のいずれかの場所にただ一つだけ記憶されており,変数 a,b はその(オブジェクトの)アドレスを指していることになります.つまり,変数 a,b は,C/C++ におけるポインタと非常に似ています(下の左図).従って,変数 b の値を変数 a に代入しても( 05 行目),その結果は変わりません.また,変数 b の値を変更すると( 08 行目),変数 b は異なる整数リテラル 20 を指すことになり,両者はいずれの比較においても異なってきます( 09,10 行目,下の右図).当然,変数 b の値を変更しても,変数 a の値は変化しません( 11,12 行目).下の左図の状態において,リテラル 10 を直接修正すれば,変数 a と b の値が同時に変化するはずですが,それを実行する演算子が存在しない,リテラルの値を修正できない,などの点から,Python では不可能です.

        しかし,浮動小数点の場合は多少異なってきます.変数 c や d がポインタであることに違いはないのですが,13 行目~ 16 行目から明らかなように,全く同じ値のリテラルであっても,異なる場所に記憶されている(異なるオブジェクトである)ことを意味します(下の左図).ただし,変数 d を変数 c に代入すれば,整数の場合と同じような状態になります( 17 行目~ 19 行目,下の右図).

        下に示すのは,C/C++ によって,上と似たような内容のプログラムを書いた例です.01 行目~ 07 行目では,const 指定によって,Python のように,定数の値を変更できなくしています.08 行目~ 14 行目のように変更可能に設定すると,13 行目に示すように,ポインタを介して変数 cc10 の値を変更可能になります.この場合,変数 a2 と b2 は同じ場所を指していますので,a2 が指す値も変化します.先ほど,Python における変数がポインタと似ていると話しましたが,このプログラムに見るように,多少異なっています.
      		// const
      01	const int c10 = 10, c20 = 20;
      02	const int *a1, *b1;   // a1,b1 は int 型に対するポインタ
      03	a1 = &c10;   // Python における a = 10 に対応
      04	b1 = &c10;   // Python における b = 10 に対応
      05	printf("%d %d\n", *a1, *b1);   // 出力は 10 10(間接演算子 * の使用)
      06	b1 = &c20;   // Python における b = 20 に対応
      07	printf("%d %d\n", *a1, *b1);   // 出力は 10 20(間接演算子 * の使用)
      		// const でない
      08	int cc10 = 10;
      09	int *a2, *b2;
      10	a2 = &cc10;
      11	b2 = a2;   // a2 と b2 の値(アドレス)が等しくなる
      12	printf("%d %d\n", *a2, *b2);   // 出力は 10 10(間接演算子 * の使用)
      13	*b2 = 20;   // ポインタ a1 が指す値も変化(間接演算子 * の使用)
      14	printf("%d %d\n", *a2, *b2);   // 出力は 20 20(間接演算子 * の使用)
      				
        次に,リストのオブジェクトを代入する場合について考えてみます.下に示すプログラムの 02 ~ 03 行目,または,04 行目,いずれの方法で代入を行っても,05 行目のように y の要素を変更した場合,変化するのは y の要素だけです.この関係のイメージは,下図のようになります.

      01	# -*- coding: UTF-8 -*-
      02	x = [1, 2, 3]
      03	y = [1, 2, 3]
      04	# x, y = [1, 2, 3], [1, 2, 3]
      05	y[0] = 10
      06	print(x, y)   # [1, 2, 3] [10, 2, 3]
      				
        しかし,下に示すプログラムの 02 ~ 03 行目,または,04 行目,いずれか方法で代入を行った場合,05 行目のように y の要素を変更した場合,対応する x の要素も変化します.これは,これらの方法で代入を実行した場合,オブジェクトに対する参照(アドレス)がコピーされ,同じオブジェクトを指すことになっているからです.C/C++ 風に言えば,同じオブジェクトに対するポインタがコピーされ代入されたことになります.この関係のイメージは,下図のようになります.

      01	# -*- coding: UTF-8 -*-
      02	x = [1, 2, 3]
      03	y = x
      04	# x = y = [1, 2, 3]
      05	y[0] = 10
      06	print(x, y)   # [10, 2, 3] [10, 2, 3]
      				
        これを避けるためには,04 行目に示すように,copy メソッドを使用し,x が参照しているオブジェクトのコピー(浅いコピー)を新たに生成し,それに対する参照を y に代入することです.04 行目の処理は,copy モジュールを使用した 02,05 行目の処理と同等です.この処理によって,最初に示した代入文と同じような状態になり,y の値を変更しても x の値は変化しません.
      01	# -*- coding: UTF-8 -*-
      02	# import copy
      03	x = [1, 2, 3]
      04	y = x.copy()   # y = x[:] と同じ
      05	# y = copy.copy(x)
      06	y[0] = 10
      07	print(x, y)   # [1, 2, 3] [10, 2, 3]
      				
        しかし,浅いコピーにおいては,オブジェクト内に存在するオブジェクトに対しては,その参照(下図における ad11 と ad12 の部分,アドレス)をコピーしているだけですので,以下に示す 2 次元のリスト(配列)のような場合は,上と同じ問題が発生します.

      01	# -*- coding: UTF-8 -*-
      02	x = [[1, 2, 3], [4, 5, 6]]
      03	y = x.copy()
      04	y[0][0] = 10
      05	print(x,y)   # [[10, 2, 3], [4, 5, 6]] [[10, 2, 3], [4, 5, 6]]
      				

        1 次元のリスト(配列)の場合であっても,各要素がクラスのオブジェクトである場合は,以下に示すように,同じような問題が発生します.クラスのオブジェクトを要素とした場合,各要素にはオブジェクトに対するアドレスが記憶されています.浅いコピーは,x の各要素の値(アドレス,参照)をコピーして新しい配列 y を生成します.その際,各要素に記憶されているアドレスが指すオブジェクト自身はコピーされません.そのため,x と y の各要素は,同じオブジェクトを指すことになります.y[1] のように,新しいオブジェクト(のアドレス)を代入した場合( 10 行目),x はその影響を受けませんが,y[2] のような変更( 11 行目)は,x[2] と y[2] が同じオブジェクトを指しているため,x[2] の値も変化します.
      01	# -*- coding: UTF-8 -*-
      02	import copy
      03	
      04	class Example :
      05	    def __init__(self, x) :
      06	        self.x = x
      07	
      08	x      = [Example(1), Example(2), Example(3)]
      09	y      = copy.copy(x)
      10	y[1]   = Example(4)
      11	y[2].x = 5
      12	print(x[0].x, x[1].x, x[2].x)   # 1 2 5
      13	print(y[0].x, y[1].x, y[2].x)   # 1 4 5
      				
        以上の問題を避けるためには,オブジェクト内に存在するオブジェクトに対しても,浅いコピーと同じ処理を行ってやることです.それが,深いコピーです(下図は,2 次元配列に対するイメージ).

      01	# -*- coding: UTF-8 -*-
      02	import copy
      03	
      04	class Example :
      05	    def __init__(self, x) :
      06	        self.x = x
      07	
      08	x = [[1, 2, 3], [4, 5, 6]]
      09	y = copy.deepcopy(x)
      10	y[0][0] = 10
      11	print(x, y)   # [[1, 2, 3], [4, 5, 6]] [[10, 2, 3], [4, 5, 6]]
      12	
      13	x      = [Example(1), Example(2), Example(3)]
      14	y      = copy.deepcopy(x)
      15	y[1]   = Example(4)
      16	y[2].x = 5
      17	print(x[0].x, x[1].x, x[2].x)   # 1 2 3
      18	print(y[0].x, y[1].x, y[2].x)   # 1 4 5
      				

      C++ の場合

        C++ 標準ライブラリ内の vector クラスを使用した C++ のプログラム例を載せておきます(出力結果は同じであるため除く).その際,出力文「 cout << 」に対しては,以下に示すように,<< 演算子のオーバーロードがされているものとします.
      ostream& operator << (ostream& stream, vector<int> &s)
      {
      	if (s.empty())
      		stream << "[]\n";
      	else {
      		stream << "[";
      		for (unsigned int i1 = 0; i1 < s.size(); i1++) {
      			stream << s[i1];
      			if (i1 < s.size()-1)
      				stream << ", ";
      		}
      		stream << "]\n";
      	}
      	return stream;
      }
      				

      C/C++ における代入操作

      			// 通常の代入
      01	vector<int> s1, s2;
      02	for(int i1 = 1; i1 <= 3; i1++)
      03		s1.push_back(i1);
      04	s2 = s1;
      05	s2[0] = 10;
      06	cout << s1;
      07	cout << s2;
      			// ポインタの代入
      08	vector<int> *ps1, *ps2;
      09	ps1 = &s1;
      10	ps2 = ps1;
      11	(*ps2)[0] = 10;
      12	cout << *ps1;   // cout << s1; でも同じ
      13	cout << *ps2;
      			// 通常の代入( 2 次元配列)
      14	vector<int> s3[2], s4[2];
      15	for(int i1 = 1; i1 <= 3; i1++)
      16		s3[0].push_back(i1);
      17	for(int i1 = 4; i1 <= 6; i1++)
      18		s3[1].push_back(i1);
      19					// s4 = s3; はできない
      20	for(int i1 = 0; i1 < 2; i1++) {
      21		for(int i2 = 0; i2 < 3; i2++)
      22			s4[i1] = s3[i1];
      23	}
      24	s4[0][0] = 10;
      25	cout << s3[0];
      26	cout << s4[0];
      			// new 演算子の使用( 2 次元配列)
      27	vector<int> *s5 = new vector<int> [2], *s6;
      28	for(int i1 = 1; i1 <= 3; i1++)
      29		s5[0].push_back(i1);
      30	for(int i1 = 4; i1 <= 6; i1++)
      31		s5[1].push_back(i1);
      32	s6 = s5;
      33	s6[0][0] = 10;
      34	cout << s5[0];
      35	cout << s6[0];
      				
      01 行目~ 07 行目

        04 行目において,表面的には,Python の場合と同様の代入を行っています.しかし,C++ の場合は,オブジェクト自身がコピーされるため,s2 の値を変更しても,s1 の値は変化しません.06,07 行目の出力結果は以下に示すとおりです.

        [1, 2, 3]
        [10, 2, 3]

      08 行目~ 13 行目

        ps1 に s1 のアドレスを代入し( 09 行目),それを ps2 に代入しています.ps1 と ps2 は同じ場所を指しているため,Python の場合と同様,ps2 を介して値を変更すると( 11 行目),s1 の値も変化します.これが,ほぼ,Python における単純な代入に相当します.12,13 行目の出力結果は以下に示すとおりです.

        [10, 2, 3]
        [10, 2, 3]

      14 行目~ 26 行目

        オブジェクト内に他のオブジェクトが存在する場合であり,C++ における 2 次元配列に対応します.配列に対して,s4 = s3 のような代入ができないため,20 行目~ 23 行目のような処理を行っています.この場合も,s4 の値を変更しても,s3 の値は変化しません.25,26 行目の出力結果は以下に示すとおりです.

        [1, 2, 3]
        [10, 2, 3]

      27 行目~ 35 行目

        2 次元配列を new 演算子を使用して生成した場合です.この場合は,s6 及び s5 がポインタであるため,s6 = s5 のような代入が可能となります.その結果,s6 と s5 は同じデータを指すことになり,s6 を介して値を変更すると,s5 が指す値も変化します.34,35 行目の出力結果は以下に示すとおりです.

        [10, 2, 3]
        [10, 2, 3]

    2. del 文

        オブジェクトを削除します.
      >>> a, b, c = 10, 20, 30
      >>> a, b, c
      (10, 20, 30)
      >>> del a, b
      >>> a, b, c
      Traceback (most recent call last):
        File "%lt;stdin>", line 1, in <module>
      NameError: name 'a' is not defined
      				

      C++ の場合

      int *a = new int;
      *a = 10;
      cout << (*a) << endl;
      delete a;
      cout << (*a);   // 値は未定
      				

    3. import 文

        モジュールを取り込みます.
      >>> import math   # math モジュールの取り込み
      >>> math.sqrt(2)
      1.4142135623730951
      >>> import math as ma   # math モジュールを ma というモジュール名として取り込む
      >>> ma.sqrt(2)
      1.4142135623730951
      >>> from math import sqrt, fabs   # math モジュールからメソッド sqrt,fabs を取り込む
      >>> sqrt(2)
      1.4142135623730951
      >>> fabs(-10)
      10.0
      >>> from math import *   # math モジュールからすべてのメソッドを取り込む
      >>> sqrt(2)
      1.4142135623730951
      >>> pow(2, 10)
      1024.0
      				

    4. pass 文

        何も行わない文です.
      >>> a = 10
      >>> def func(x) : pass
      ...
      >>> func(a)
      >>> if a == 10:
      ...    pass
      ... else:
      ...    print("test")
      ...
      >>>
      				

  3. 複合文

    1. if 文

        if 文は,式i を順に評価していき,式i が True であれば 文i を実行し,他の部分は実行しません.いずれも True でなく.else 以下が記述されていた場合は,else の後の文を実行します.いずれの文も複数の文から構成されていても構いませんが,スペースまたはタブを使用して,同じレベルの字下げを行う必要があります.ただし,文が一つの文である場合は,コロンの後ろに記述しても構いません.C/C++ における else if 文とほとんど同じです(なぜ,else if でなくて elf ?).
      if 式1 : 
          文1
      [elif 式2 : 
          文2]
      ・・・・・
      [elif 式n : 
          文n]
      [else  : 
          文]
      				
        例えば,
      # -*- coding: UTF-8 -*-
      a = int(input("データを入力してください "))   # 標準入力から 1 行入力
      if a < 0 :
          print("負")
      elif a == 0 :
          print("0")
      else :
          print("正")
      				
      のような内容のファイル test.py を作成し,Window のコマンドプロンプト上で,
      py -3 test.py
      				
      と入力すれば,
      データを入力してください
      				
      というメッセージが出力されますから,例として,
      10
      				
      と入力すれば,以下のような結果が得られるはずです.

      C++ の場合

      int a;
      cout << "データを入力してください ";
      cin >> a;
      if (a < 0) {   // 文iが 1文の時は {} は必要ない
          cout << "負\n";
      }
      else if (a == 0) {
          cout << "0\n";
      }
      else {
          cout << "正\n";
      }
      				
        if 文に対するもう少し具体的な例として,2 次方程式を解くためのプログラムを挙げておきます.
      # -*- coding: UTF-8 -*-
      from math import *
      		# 係数の読み込み
      st = input("係数a,b,及び,c は? ")
      lt = st.split()
      a  = float(lt[0])
      b  = float(lt[1])
      c  = float(lt[2])
      		# 一次方程式
      if abs(a) <= 1.0e-10 :
      	if abs(b) <= 1.0e-10 :
      		print("   解を求めることができません!\n")
      	else :
      		x = -c / b;
      		print("   x = " + str(x) + "\n")
      		# 二次方程式
      else :
      	d = b * b - 4.0 * a * c
      			# 重根
      	if abs(d) < 1.0e-10 :
      		x = -0.5 * -b / a
      		print("   x = " + str(x) + "\n")
      			# 2実根
      	elif d >= 0.0 :
      		d  = sqrt(d)
      		x1 = 0.5 * (-b - d) / a
      		x2 = 0.5 * (-b + d) / a
      		print("  x = " + str(x1) + " " + str(x2) + "\n")
      			# 虚根
      	else :
      		d  = sqrt(-d);
      		x1 = -0.5 * b / a
      		x2 = 0.5 * d / a
      		print("  x = " + str(complex(x1,x2)) + " " + str(complex(x1,-x2)) + "\n")
      				

      C++ の場合

      int main()
      {
      	double a, b, c, d, x, x1, x2;
      		// 係数の読み込み
      	printf("係数a,b,及び,c は? ");
      	scanf("%lf %lf %lf", &a, &b, &c);
      		// 一次方程式
      	if (fabs(a) <= 1.0e-10) {
      		if (fabs(b) <= 1.0e-10)
      			printf("   解を求めることができません!\n");
      		else {
      			x = -c / b;
      			printf("   x = %f\n", x);
      		}
      	}
      		// 二次方程式
      	else {
      		d = b * b - 4.0 * a * c;
      			// 重根
      		if (fabs(d) < 1.0e-10) {
      			x = -0.5 * -b / a;
      			printf("   x = %f\n", x);
      		}
      			// 2実根
      		else if (d >= 0.0) {
      			d  = sqrt(d);
      			x1 = 0.5 * (-b - d) / a;
      			x2 = 0.5 * (-b + d) / a;
      			printf("  x = %f %f\n", x1, x2);
      		}
      			// 虚根
      		else {
      			d  = sqrt(-d);
      			x1 = -0.5 * b / a;
      			x2 = 0.5 * d / a;
      			printf("   x = %f ± %fj\n", x1, x2);
      		}
      	}
      	return 0;
      }
      				

    2. while 文

        while 文は,式を評価し,式が True である限り 文1 の実行を繰り返します.式が False になり,else 以下が記述されていた場合は 文2 を実行し,また,記述されていなかった場合は何も行わず,繰り返しを終了します.いずれの文も複数の文から構成されていても構いませんが,スペースまたはタブを使用して,同じレベルの字下げを行う必要があります.ただし,文が一つの文である場合は,コロンの後ろに記述しても構いません.C/C++ における while 文とほとんど同じですが,C/C++ には,else 以下の部分がありません.

        文1 の実行の途中で break 文が実行されると,文1 の残りの部分を実行せず,現在実行中の while 文から抜け出します( else 以下は実行されない).また,文1 の実行の途中で continue 文が実行されると,文1 の残りの部分を実行せず,式の真偽評価に移ります.
      while : 
          文1
      [else  : 
          文2]
      				
        例えば,以下に示す内容のスクリプトファイルを実行すると,正のデータが入力されるまで入力を促すことが繰り替えされるはずです.また,0 を入力しても while 文から抜け出しますが,else に対応する箇所は実行されません.
      # -*- coding: UTF-8 -*-
      a = -1
      b = 0
      while a <= 0 :
      	a = int(input("data? "))
      	if a == 0 :
      		break
      else :
      	b = 1 / a
      print(b)
      				
        次は,入力されたデータの内,負のデータの最大値を求めるためのプログラムです.99999 を入力するとプログラムを終了します.単なる最大値を求める場合は組み込み関数 max を使用すれば簡単に求めることができますが,この例のように,条件付きの最大値に関してはプログラムを書かざるを得ません.
      # -*- coding: UTF-8 -*-
      sw = 0
      x  = 0
      while x != 99999 :
      	x = int(input("データを入力してください "))
      	if x < 0 and (sw == 0 or x > max) :
      		max = x
      		sw  = 1
      print("   最大値 = " + str(max))
      				

      C++ の場合

      int main()
      {
      	int max, sw = 0, x = 0;   // maxに対する初期設定は不要
      	while (x != 99999) {
      		printf("データを入力してください ");
      		scanf("%d", &x);
      		if (x < 0 && (sw == 0 || x > max)) {
      			max = x;
      			sw  = 1;
      		}
      	}
      	printf("   最大値=%d\n", max);
      	return 0;
      }
      				

    3. for 文

        for 文は,イテラブルオブジェクト内の要素が順に変数に代入され,要素が空になるまで,文1 が繰り返し実行されます.要素が空になり,else 以下が記述されていた場合は 文2 を実行し,また,記述されていなかった場合は何も行わず,繰り返しを終了します.いずれの文も複数の文から構成されていても構いませんが,スペースまたはタブを使用して,同じレベルの字下げを行う必要があります.ただし,文が一つの文である場合は,コロンの後ろに記述しても構いません.C++ における範囲 for 文と似た機能を持った文ですが,通常の for 文の形式が使用できないのには,多少の抵抗を感じます.意味の無い記号に新規の機能を持たせるようなことを数多く行っているにもかかわらず,なぜ,多くの人にとって使い慣れた for 文の仕様を変更する必要があるのでしょうか.なお,iterableイテラブル)とは,リストタプルrange など,構成要素を一度に一つずつ返すことができるオブジェクトです.

        文1 の実行の途中で break 文が実行されると,文1 の残りの部分を実行せず,現在実行中の for 文から抜け出します( else 以下は実行されない).また,文1 の実行の途中で continue 文が実行されると,文1 の残りの部分を実行せず,次の要素による 文1 の実行に移ります.
      for 変数 in イテラブルオブジェクト : 
          文1
      [else  : 
          文2]
      				
        例えば,以下に示すいずれの方法においても,希望する出力が得られるはずです.
      >>> for x in [1, 2, 3] :   # list
      ...     print(x)
      ...
      1
      2
      3
      >>> for x in (1, 2, 3) :   # tuple
      ...     print(x)
      ...
      1
      2
      3
      >>> for x in range(1, 4) :   # range
      ...     print(x)
      ...
      1
      2
      3
      				

      C++ の場合

      int x[] = {1, 2, 3};
      vector<int> y = {1, 2, 3};
      for (auto e : x)   // for (auto e : {1, 2, 3}) も OK
      	cout << e << endl;
      for (auto e : y)   // vector
      	cout << e << endl;
      for (int i1 = 1; i1 < 4; i1++)  // range
      	cout << i1 << endl;
      				
        次は,試験の平均点を計算した後,平均点以上の人数を求めるためのプログラムです.入力された点はリストに保存した後,平均点以上の人数を求める際に使用しています.なお,負の値を入力すると,プログラムを終了します.
      # -*- coding: UTF-8 -*-
      x = 0
      sum = 0.0
      v = []
      		# データの読み込み
      while x >= 0 :
      	x = int(input("点数は? "))
      	sum += x;
      	if x >= 0 :
      		v.append(x);
      		# 平均値以下の人数
      sum /= len(v)
      print("   平均値は " + str(sum))
      n = 0
      for i1 in range(0, len(v)) :
      	if v[i1] <= sum :
      		n += 1
      print("   平均値以下の人数は " + str(n))
      				

      C++ の場合

      int main()
      {
      	int x = 0;
      	double sum = 0.0;
      	vector<int> v;
      		// データの読み込み
      	while (x >= 0) {
      		printf("点数は? ");
      		scanf("%d", &x);
      		sum += x;
      		if (x >= 0)
      			v.push_back(x);
      	}
      		// 平均値以下の人数
      	sum /= v.size();
      	printf("   平均値は %f\n", sum);
      	int n = 0;
      	for (unsigned int i1 = 0; i1 < v.size(); i1++) {
      		if (v[i1] <= sum)
      			n++;
      	}
      	printf("   平均値以下の人数は %d\n", n);
      	return 0;
      }
      				
        下に示すのは,行列の加算,減算,乗算を行うプログラムです.NumPy の matrix を使用すれば,より簡潔に記述できますが,ここでは,多重ループの例としてリストを使用して記述しています.
      # -*- coding: UTF-8 -*-
      		# 設定
      A = [[1, 2, 3], [4, 5, 6]]
      B = [[0, 0, 0], [4, 5, 6]]
      C = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
      D = [[0, 0, 0], [0, 0, 0]];
      		# 演算
      print("*** A ***")
      print(A)
      print("*** B ***")
      print(B)
      print("*** C ***")
      print(C)
      print("*** A+B ***")   # 行列の加算
      for i1 in range(0, 2) :
      	for i2 in range(0, 3) :
      		D[i1][i2] = A[i1][i2] + B[i1][i2]
      print(D)
      print("*** A-B ***")   # 行列の減算
      for i1 in range(0, 2) :
      	for i2 in range(0, 3) :
      		D[i1][i2] = A[i1][i2] - B[i1][i2]
      print(D)
      print("*** A*C ***")   # 行列の乗算
      for i1 in range(0, 2) :
      	for i2 in range(0, 3) :
      		D[i1][i2] = 0
      		for i3 in range(0, 3) :
      			D[i1][i2] += A[i1][i3] * C[i3][i2]
      print(D)
      				

      C++ の場合

      int main()
      {
      		// 設定
      	double A[2][3] = {{1, 2, 3}, {4, 5, 6}};
      	double B[2][3] = {{0, 0, 0}, {4, 5, 6}};
      	double C[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
      	double D[2][3];
      		// 演算
      	cout << "*** A ***\n";
      	for (int i1 = 0; i1 < 2; i1++)
      		printf("%5.0f %5.0f %5.0f\n", A[i1][0], A[i1][1], A[i1][2]);
      	cout << "*** B ***\n";
      	for (int i1 = 0; i1 < 2; i1++)
      		printf("%5.0f %5.0f %5.0f\n", B[i1][0], B[i1][1], B[i1][2]);
      	cout << "*** C ***\n";
      	for (int i1 = 0; i1 < 3; i1++)
      		printf("%5.0f %5.0f %5.0f\n", C[i1][0], C[i1][1], C[i1][2]);
      	cout << "*** A+B ***\n";   // 行列の加算
      	for (int i1 = 0; i1 < 2; i1++) {
      		for (int i2 = 0; i2 < 3; i2++)
      			D[i1][i2] = A[i1][i2] + B[i1][i2];
      	}
      	for (int i1 = 0; i1 < 2; i1++)
      		printf("%5.0f %5.0f %5.0f\n", D[i1][0], D[i1][1], D[i1][2]);
      	cout << "*** A-B ***\n";   // 行列の減算
      	for (int i1 = 0; i1 < 2; i1++) {
      		for (int i2 = 0; i2 < 3; i2++)
      			D[i1][i2] = A[i1][i2] - B[i1][i2];
      	}
      	for (int i1 = 0; i1 < 2; i1++)
      		printf("%5.0f %5.0f %5.0f\n", D[i1][0], D[i1][1], D[i1][2]);
      	cout << "*** A*C ***\n";   // 行列の乗算
      	for (int i1 = 0; i1 < 2; i1++) {
      		for (int i2 = 0; i2 < 3; i2++) {
      			D[i1][i2] = 0;
      			for (int i3 = 0; i3 < 3; i3++)
      				D[i1][i2] += A[i1][i3] * C[i3][i2];
      		}
      	}
      	for (int i1 = 0; i1 < 2; i1++)
      		printf("%5.0f %5.0f %5.0f\n", D[i1][0], D[i1][1], D[i1][2]);
      
      	return 0;
      }
      				

    4. with 文

        with 文は,ブロックの実行をコンテキストマネージャによって定義されたメソッドでラップするために使われます.コンテキストマネージャは,コードブロックを実行するために必要な入り口および出口の処理を扱います.簡単に言えば,ブロックの実行を,簡単かつ安全に実行させるための文です.代表的な使い方として,様々なグローバル情報の保存および更新,リソースのロックとアンロック,ファイルのオープンとクローズなどが挙げられます.

        次に示すのは,ファイルのオープンとクローズの例です.with ブロックに入る際にファイルがオープンされ,ブロックを出ると自動的にファイルがクローズされます.
      >>> with open("test.txt", "r") as f :
      ...    a = f.read()
      ...
      >>> a
      '10 20 30\n菅沼義昇\n'
      >>> f.closed
      True   # 既にクローズされている
      				

    5. try 文

        try 文は,例外処理を行うための文です.以下の例は,while 文で挙げた例と同じように,適切な値が入力されるまで,入力を促すことが繰り返されます.
      # -*- coding: UTF-8 -*-
      while True :
          try :
              x = int(input("整数を入力して下さい: "))
              break
          except ValueError :
              print("   不適切なデータです!")
      print(x)
      				

      C++ の場合

      double x;
      while (true) {
      	try {
      		cout << "整数を入力して下さい: ";
      		cin >> x;
      		if (x-(int)x != 0.0) {
      			char *str = "   不適切なデータです!\n";
      			throw str;
      		}
      		else
      			break;
      	}
      	catch (char *str)
      	{
      		cout << str;
      	}
      }
      cout << x << endl;
      				

静岡理工科大学 菅沼ホーム 目次 索引