C#をPythonと比較して学ぶ(第二回:処理)

2024/02/01 C# Python 比較シリーズ

はじめに

第一回記事では、C#とPythonのデータの取り扱いに焦点を当て、基本的なプログラミング原則を解説しました。今回は、プログラムの処理に関する概念を掘り下げていきます。言語ごとの処理フローの違いや基本的な制御構造を比較し、それによるプログラムの挙動の違いについて学びます。



第二回記事の概要

第二回記事では、プログラムの処理にフォーカスし、順次、選択、反復といった基本的な処理フローについて解説します。まず、コードの実行方法について説明し、その後にC#とPythonの基本的な制御構造に焦点を当てます。条件分岐や繰り返し処理の概念を理解し、実際のコード例を通じて言語ごとの特徴を比較します。

また、エラーの種類やデバッグについても触れ、プログラミングにおいて発生しうる問題にどのように対処すべきかを解説します。これにより、効果的なデバッグ手法を習得し、より信頼性の高いプログラムを構築できるようになるでしょう。

これらの内容を通じて、プログラムの処理の流れやエラーへの対処法を理解し、実際の開発においてよりスムーズに作業できるようになることを目指します。


順次のプログラム処理

順次のプログラム処理は基本的に、コードが上から下へ順番に実行されるという考え方です。プログラムを読むときも上から下へと流れていくため、順次の理解はプログラミングの出発点と言えます。

プログラミング言語には、主に「インタプリタ言語」と「コンパイラ言語」の2つの種類があります。


インタプリタ言語とは?

インタプリタ言語は、プログラムを実行するときにその都度ソースコードを解釈し、逐次実行する言語です。Pythonは典型的なインタプリタ言語の例です。Pythonのスクリプトは、実行されるたびにインタプリタが逐次コードを解釈し、実行します。


コンパイラ言語とは?

コンパイラ言語は、プログラムをコンパイルと呼ばれる工程を経て、機械語やバイトコードに変換され、その後実行されます。C#はコンパイラ言語の一例です。C#のプログラムは事前にコンパイルされて実行可能ファイルが生成され、それが実行されます。

具体的にC#での順次の処理を示します。まず、基本的なC#プログラムの骨組みは以下の通りです。

using System;

class Program
{
    static void Main()
    {
        // ここからプログラムが始まる
        Console.WriteLine("Hello, C#!"); // 画面に文字列を表示

        // ここにさまざまな処理を順次追加
    }
}

このプログラムではMainメソッドが実行され、その中に書かれたコードが上から下へと順次実行されます。C#の場合、基本的にはMainメソッドから処理が始まります。

また、C#には例外的な特徴として「トップレベルステートメント」があります。これはMainメソッドの外にも直接コードを書くことができ、その場合も順次実行されます。例えば、以下のようにトップレベルステートメントを使うことができます。

using System;

Console.WriteLine("Hello from top-level statement!");

// 以下にさまざまな処理を順次追加

これは、トップレベルステートメントが自動的にMainメソッド内に組み込まれ、実行される仕組みがあるためです。

一方、Pythonでは通常、スクリプトの最上位に以下のような慣習的なコードが書かれます。

def main():
    # ここからプログラムが始まる
    print("Hello, Python!")

if __name__ == "__main__":
    main()

Pythonではファイルがスクリプトとして直接実行されるか、モジュールとして他のスクリプトから読み込まれるかで、処理の開始位置が変わります。if __name__ == "__main__":は、スクリプトが直接実行される場合にmain()関数を呼び出すための仕組みです。

これにより、C#とPythonとでどの部分から処理が始まるか、順次のプログラム処理の特徴が明らかになります。


C#のセミコロンとステートメント

C#において、セミコロン(;)はステートメント(文)の終了を示す記号です。C#は文末にセミコロンを置かないと構文エラーが発生します。ステートメントは基本的に1つの命令を表し、その終了を示すのがセミコロンです。

以下は、さきほど挙げたコードの再掲です。

using System;

class Program
{
    static void Main()
    {
        // ここからプログラムが始まる
        Console.WriteLine("Hello, C#!"); // セミコロンでステートメントの終了

        // 以下にさまざまな処理を順次追加
    }
}

ここで、Console.WriteLine("Hello, C#!");のような行末にセミコロンがついています。このセミコロンは、Console.WriteLineメソッド呼び出し文が終了したことを示しています。C#は文が終わるごとにセミコロンが必要なので、これによってどこで1つのステートメントが終了し、次のステートメントが始まるかが区別されます。

C#のセミコロンの役割は、文法の一貫性を保ちつつ、複数のステートメントを同じ行に書くことができるようにすることにあります。例えば、以下のように複数のステートメントを同じ行に書くこともできます

int x = 5; Console.WriteLine(x); // セミコロンでステートメントの区切り

このようにして、C#ではセミコロンがステートメントの終了を示す重要な要素となっています。


セミコロンの歴史とC#での役割

セミコロンの歴史は、プログラミング言語の進化とともに形成されました。初期のプログラミング言語では、文の終わりを示すための具体的な記号は必ずしも存在していませんでした。しかし、ALGOL60(1960年代)の登場により、セミコロンが文の区切りを示すための標準的な要素として導入されました。

ALGOL60の設計では、セミコロンが文の終端を示すためのマークとして採用されました。ALGOL60は、文法の規格を作成する際にBNF(Backus-Naur Form)と呼ばれる文法記述法を使用し、この中でセミコロンが文の区切りを示すために利用されました。

この影響を受けて、後に登場したC言語(1972年)もセミコロンを文の終端として採用しました。C言語の仕様とコンパイラがシンプルであったこと、そしてUnixなどに広く移植されたことが、セミコロンが広く使われる契機となりました。

C#(C Sharp)はC言語を基にしており、そのためC#もまたセミコロンを文の終端として使用します。C#のセミコロンは、文の区切りを示すだけでなく、C#のコンパイラが正確に文を解釈するための必須の要素となっています。

セミコロンの導入により、プログラムの構造がより整然とし、効率的なコンパイルが可能となりました。その後の多くのプログラミング言語でも、文の終端を示すためにセミコロンが採用され、プログラマにとって習慣的かつ重要な要素となりました。


条件分岐に関するC#とPythonの比較

条件式の書き方:

C#:

C#では条件式を評価するために、比較演算子(==, !=, <, >, <=, >=)が使われます。例えば、x == yはxがyと等しいかどうかを評価します。

int x = 5;
int y = 10;

Console.Writeline(x == y);  //false
Console.Writeline(x != y);  //not equal → true
Console.Writeline(x <= y);  //≦ → true

Python:

Pythonも同様に比較演算子(==, !=, <, >, <=, >=)が使用されます。x == yはxがyと等しいかどうかを評価します。

x = 5
y = 10

print(x == y)  #false

==と=の違いについて:

C#:

C#では==は等価性を比較するための演算子であり、=は代入演算子です。=を誤って等価性の比較に使用するとコンパイルエラーになります。

Python:

Pythonでも==は等価性を比較するための演算子であり、=は代入演算子です。Pythonではこの違いに関して厳密なチェックは行われませんが、プログラマが混同すると予期せぬ動作が発生する可能性があります。


if文の書き方とelse if, elseの書き方:

C#:

C#ではif文の基本構造は以下の通りで、else ifやelseは任意です。

if (条件1)
{
    // 条件1が真の場合の処理
}
else if (条件2)
{
    // 条件2が真の場合の処理
}
else
{
    // どの条件も満たさない場合の処理
}

Python:

Pythonも同様にif文の基本構造は以下の通りで、elifやelseは任意です。

if 条件1:
    # 条件1が真の場合の処理
elif 条件2:
    # 条件2が真の場合の処理
else:
    # どの条件も満たさない場合の処理

OR演算子とAND演算子の比較:

C#:

C#ではOR演算子は||、AND演算子は&&です。

if (条件1 || 条件2)
{
    // 条件1または条件2が真の場合の処理
}

if (条件1 && 条件2)
{
    // 条件1かつ条件2が真の場合の処理
}

Python:

PythonではOR演算子はor、AND演算子はandです。

if 条件1 or 条件2:
    # 条件1または条件2が真の場合の処理

if 条件1 and 条件2:
    # 条件1かつ条件2が真の場合の処理

条件演算子、三項演算子の書き方の比較:

C#:

C#では条件演算子(三項演算子)は条件 ? 真の場合の値 : 偽の場合の値で表します。

int x = 5;
int y = (x > 0) ? 10 : 20;    // xが0より大きい場合は10、そうでない場合は20

//同義のif文
if (x>0) 
{ y=10 }
else
{ y=20 }

Python:

Pythonでも同様に条件演算子は真の場合の値 if 条件 else 偽の場合の値で表します。

x = 5
y = 10 if x > 0 else 20  # xが0より大きい場合は10、そうでない場合は20

#同義のif文
if x>0:
y=10

else:
y=20

C#のswitch文:

C#では、switch文は特定の式の値に基づいてプログラムのフローを制御します。以下に基本的な使い方を示します。

int day = 3;

switch (day)
{
    case 1:
        // dayが1の場合の処理
        break;
    case 2:
        // dayが2の場合の処理
        break;
    case 3:
        // dayが3の場合の処理
        break;
    default:
        // どのcaseにも該当しない場合の処理
        break;
}

上記の例では、変数dayの値によって異なる処理が行われます。break;は処理を終了し、次のcaseまたはdefaultに進みます。


同義のif文:

同じ動作をするif文での表現は以下の通りです。

int day = 3;

if (day == 1)
{
    // dayが1の場合の処理
}
else if (day == 2)
{
    // dayが2の場合の処理
}
else if (day == 3)
{
    // dayが3の場合の処理
}
else
{
    // どの条件にも該当しない場合の処理
}

switch文と同じ条件分岐をif文で表現しました。しかし、switch文の方が見やすく、処理が効率的です。

Pythonでは、C#のようなswitch文の明示的な構造がないため、if文が頻繁に使われます。


反復

プログラムにおいて反復処理は根幹をなしている処理です。その際for文が代表的に使われる構文です。


C#のfor文:

C#でのfor文は通常、以下のようにインデックスを増やして利用されます。

for (int i = 0; i < 5; i++)  //(始まり; 終わり; 変化のさせ方)
{
    // インデックスiを使用した処理
}

上記の例では、iが0から4まで変化します。i++はiを1ずつ増加させます。


Pythonのfor文:

Pythonのfor文は直感的であり、以下のように使います。

for i in range(5):
    # インデックスiを使用した処理

range(5)は0から4までの数値を生成します。


C#のfor each文:

コレクションに対するfor each文は次のようになります。

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

foreach (var number in numbers)
{
    // numberを使用した処理
}

foreach文はコレクションの各要素に対して反復します。


Pythonのfor文でのinの使い方:

Pythonのfor文ではinを使用してコレクションの各要素にアクセスします。

numbers = [1, 2, 3, 4, 5]

for number in numbers:
    # numberを使用した処理

C#でのbreak, continueの使い方:

breakとcontinueはfor文やwhile文などで使用され、breakはループを終了し、continueは次の反復に進みます。

for (int i = 0; i < 5; i++)
{
    if (i == 3)
        break; // iが3のときループを終了

    if (i == 1)
        continue; // iが1のとき処理を飛ばして、次の反復に進む

    // インデックスiを使用した処理
}

Pythonでのbreak, continueの使い方:

breakとcontinueは同様に使用され、breakはループを終了し、continueは次の反復に進みます。

for i in range(5):
    if i == 3:
        break  # iが3のときループを終了

    if i == 1:
        continue  # iが1のとき処理を飛ばして、次の反復に進む

    # インデックスiを使用した処理

Pythonでのenumerateやzipの使い方:

enumerateはインデックスと要素を同時に取得し、zipは複数のコレクションを同時に反復します。

string_list = ["one", "two", "three"]

for index, value in enumerate(string_list):
    # indexとvalueを使用した処理 (例:index=0, value="one"; index=1, value="two"; index=2, value="three")

numbers = [1, 2, 3]
words = ["one", "two", "three"]

for number, word in zip(numbers, words):
    # numberとwordを使用した処理   (例:number=1, word="one"; number=2, word="two"; number=3, word="three";)

C#でのforeachでのindex取得:

Selectメソッドを使用してforeachでのindexを得ることができます。

List<string> stringList = new List<string> { "one", "two", "three" };

foreach (var (value, index) in stringList.Select((value, index) => (value, index)))
{
    // valueとindexを使用した処理
}

C#での複数コレクションでのforeach:

複数のコレクションに対するforeach文はZipメソッドを使用します。

List<int> numbers = new List<int> { 1, 2, 3 };
List<string> words = new List<string> { "one", "two", "three" };

foreach (var (number, word) in numbers.Zip(words, (number, word) => (number, word)))
{
    // numberとwordを使用した処理
}

while文とfor文の違い:

while文とfor文は両方とも反復処理を行いますが、主な違いは反復の仕組みです。for文はあらかじめ指定された回数だけ繰り返し、while文は条件が満たされている限り繰り返します。


C#でのwhile文:

C#でのwhile文は以下のように表記されます。

int i = 0;
while (i < 5)
{
    // 条件(i < 5)が満たされている限り繰り返し
    // iを使用した処理
    i++;
}

上記の例ではiが0から4まで変化します。i++はiを1ずつ増加させます。


Pythonでのwhile文:

Pythonでのwhile文も直感的であり、以下のように表記されます。

i = 0
while i < 5:
    # 条件(i < 5)が満たされている限り繰り返し
    # iを使用した処理
    i += 1

C#と同様に、iが0から4まで変化します。i += 1はiを1ずつ増加させます。


do while文とは:

do while文は最低でも1回は処理を実行し、その後条件をチェックして繰り返す構造です。


C#でのdo while文:

C#でのdo while文は以下のように表記されます。

int j = 0;
do
{
    // 条件が満たされている限り繰り返し
    // jを使用した処理
    j++;
} while (j < 5);

doの後に処理が続き、その後にwhileで条件を指定します。この構造は条件が最初に満たされていなくても、最低でも1回は処理が実行されます。


Pythonでのdo while文:

Pythonには明示的なdo while文は存在しませんが、同様の動作を実現するためにwhile Trueを使用し、途中でbreakで終了条件を設定する方法があります。

j = 0
while True:
    # 条件が満たされている限り繰り返し
    # jを使用した処理
    j += 1
    if j >= 5:
        break

while Trueは無限ループを意味し、途中でbreakを使ってループを抜ける形でdo whileのような挙動を実現しています。


エラーとデバッグ:

エラーはプログラムの開発において避けて通れない要素であり、ビルドエラー、実行時エラー、論理エラーの3つの主要なカテゴリがあります。以下では、C#とPythonにおけるそれぞれのエラーについて説明し、比較します。


ビルドエラー:

C#の場合:

C#におけるビルドエラーは主にコンパイルエラーの形で現れます。これは文法の誤り、タイポ、メソッドが見つからないなどの問題により、ソースコードをコンパイルできない場合に発生します。

// 例: 文法ミス
int x = "Hello"; // コンパイルエラー: 予期しない型

Pythonの場合:

Pythonは動的型付け言語であり、ビルドエラーが発生することは少ないです。ただし、依存するライブラリやモジュールが存在しない場合、実行時にエラーとなります。

# 例: モジュールが見つからない
import non_existent_module  # ModuleNotFoundError

実行時エラー:

C#の場合:

C#における実行時エラーは、プログラムが実行されている最中に発生します。例えば、配列の範囲外へのアクセスやゼロでの割り算などが該当します。

// 例: 配列の範囲外
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]);  // IndexOutOfRangeException

Pythonの場合:

Pythonも実行時エラーが発生します。例えば、リストの範囲外へのアクセスやゼロでの割り算などが該当します。

# 例: リストの範囲外
numbers = [1, 2, 3]
print(numbers[5])  # IndexError

論理エラー:

C#とPythonの場合:

論理エラーはプログラムが正常に動作しているように見えますが、プログラマーの意図に反する結果が得られる場合に発生します。例えば、計算式やアルゴリズムの誤りが該当します。

// 例: 論理エラー
float weight = -20.0f;
float height = 183.0f;
float BMI = weight / (height/100 * height/100);  // -5.972 実行時エラーではないが、BMIが負の値となり、プログラムの意図に反する結果
# 例: 論理エラー
weight = -20.0
height = 183.0
BMI = weight / (height/100 ** 2);  # -5.972 実行時エラーではないが、BMIが負の値となり、プログラムの意図に反する結果

比較:

C#は静的型付け言語であるため、ビルドエラーはコンパイル時に発見され、実行時エラーや論理エラーが発生することは少ない傾向があります。一方で、Pythonは動的型付け言語であり、実行時エラーがより柔軟に発生する可能性があります。どちらも論理エラーはコンパイル時や実行時には検知されません。デバッグ手法やテストが論理エラーの発見に役立ちます。


まとめ:

この記事では、「C#をPythonと比較して学ぶ」シリーズの第二回において、C#とPythonの基本的なコーディング構造や制御構文、エラーに焦点を当てて学びました。

まず、順次処理について触れ、C#が通常class内のmain関数から実行される一方、Pythonはトップレベルステートメントがあり、クラスに閉じられずにコードを実行できる点を理解しました。

次に、コードの構造について比較しました。C#では文の終了に;が必要であり、Pythonと異なり行末に明示的な終了記号が必要です。

選択構文としてのif文では、C#とPythonで条件の表現方法が比較されました。C#ではif (条件) { ~ } else if (条件) { ~ } else { ~ }の形式が使われ、論理演算子も異なります。

switch文についてもC#でのswitch文の使い方や、同等の機能を持つif-else文との比較が行われました。C#のswitch文は複数の条件をスッキリと書くのに適しています。

反復処理において、C#のfor文とPythonのfor文における差異が比較されました。C#ではforeachを使用してコレクションの各要素に対する反復が行えます。 最後に、エラーとデバッグに関する項目では、ビルドエラー、実行時エラー、論理エラーについて説明され、それぞれの特徴が述べられました。

これらの比較を通じて、C#とPythonのコーディングスタイルや特徴の違いを理解し、開発時に注意が必要なポイントを把握することができました。第三回では部品化やオブジェクト指向についてまとめていこうと思います。

注:なお、私がC#について学んだことを元にしていますが、不足している部分や誤っている部分があるかもしれません。その際は、遠慮なくご指摘いただければ幸いです。



参考文献