Monthly Archives: 3月 2025

C言語プログラマのためのPython入門(第1回)

この講座は、普段、C言語でソフトウェアを開発されている「組み込みソフトウェア技術者」の皆様に向けて、pythonの活用例をご紹介する講座です。その第1回では、pythonの言語仕様について、C言語と比較しながら、ポイントをご紹介します。

関数

pythonでは、C言語と同じく、関数を記述し、実行できます。ただしC言語では、関数が必須であるのに対して、pythonでは関数を書いても良いし、書かなくても良い…という違いがあります。関数を作成せずにpythonのソースコードを書いた場合、記述順に従い、(制御文で分岐させない限り)基本、上から下に順番に実行されます。

(補足)
ソースファイルの上から順番に処理を書く場合でも、その途中に、必要に応じてに関数を書く事も可能です。この場合は、関数「以外」の処理が上から順に実行され、関数の中身は「関数呼び出し」が記述された場合のみ、その呼び出し箇所から呼ばれ、実行されます。

pythonの関数の記述例を以下に示します。

def addAndCheck_over100(var1, var2):

result = var1 + var2

isOver100 = False

if (result > 100):

isOver100 = True

return (result, isOver100)

  • 関数先頭の書式は「def 関数名(引数, …):」です。末尾のコロン’:’は必須です。引数が無い場合は括弧()内は空にします。
  • 引数や戻り値の「型宣言」は不要です。「型」については、後の節で解説します。
  • pythonでは、変数を使用する際、事前に宣言する必要は無く、いきなり「初期化」から記述できます。
  • pythonの関数の大きな特徴は、複数の値を「戻り値」として返せる点です。

上記した関数の呼び出し元の記述例は、以下です。複数の戻り値のコピー先をカンマ(,)で区切って、左から順に並べます。

value, isOver = Add_andCheck_over100(48, 32)

型宣言

C言語では、変数を宣言する際、必ずその「型」を宣言しましたが、pythonでは型宣言は不要です。
pythonにおける変数の型は、その変数に値を「代入」した時に決定されます。また既に値を代入した変数に対して、別の型の値を代入すると、その時点で変数の型が変わります。

var1 = 10

print(var1)

print(type(var1))

var1 = "ABC"

print(var1)

print(type(var1))

上記したpythonソースコード中の「type()」は、引数で指定した変数の「型名」を文字列で返す関数です。上記のソースを実行した場合、画面には以下が表示されます。

10

<class 'int'>

ABC

<class 'str'>

同じ変数var1に対して、異なる型である「文字列型」の値を代入したことで、変数の型がint型から文字列(str)型に変化しています。ただ上記のように、同じ変数に異なる型の値を代入するようなソースコードを積極的に書く必要は無く、pythonの言語仕様として、そういう特徴がある..という事だけ覚えて頂ければと思います。

ブロック

C言語では、ブロックを{}で表現しましたが、pythonでは「インデント」で表現します。すなわち、同じ階層の「インデント」が同じブロックになります。

if (a > 10):

if (b > 20):

print("OK!")

インデントは、タブまたは半角スペースで記述できますが、同じ階層のインデントは、同じ文字で記述する必要があります。たとえばタブを使った場合、その階層のインデントは、全てタブで段下げする必要がありますし、半角スペースを使った場合は、全て半角スペースで段下げする必要があります。

タブとスペースは、無理に混在させる必要は無いと思いますので(C言語でも同様)、普段お使いの文字で段下げされれば良いと思います。

文字

この後にご紹介するpythonの活用法では、テキストファイル/CSVファイル/EXCELファイル等のファイルを読み込み、処理する活用法をご紹介する予定です。それに向けた予備知識として、本節ではpythonにおける「文字」の扱いについて説明します。

C言語では「文字」が連続したものが「文字列」ですが、pythonでは1文字だけを表現する「文字型(char型)」は存在しません。pythonにおいて「文字」を扱う場合は「1文字だけの文字列」として扱う必要があります。この点は、C言語と大きく異なる点ですが、慣れてくると、特に不都合を感じる事はありません。

たとえば、文字列を先頭から1文字ずつ参照し、文字’A’ と同じか判定したい場合は、以下のように記述します。

str1 = "ABC"          # C言語の記述と似ている。ただし文字列終端のnull文字('\0')は存在しない。

length = len(str1)       # 文字列のバイト長は関数len で取得可能。結果は3。

for i in range(length):     # iの値0から2でループさせたい場合 ※for文と range()は後節で解説

if (str1[i] == "A"):    # []は「スライス」と呼ばれる。※後節で解説

print("Matched! at index:%d" % i)


(補足)

  • 文字列の前後を囲む文字は ” でも ‘ でも、どちらでも使用できます。
  • 文字列から「1文字だけの文字列」を取り出す場合は[]を使用します。これは「スライス」と呼ばれるものです。
  • スライスについては、後の節で解説します。

C言語では、1文字を判定(もしくは変換)する関数として、isdigit()、toupper() 等の関数が用意されていますが、pythonでは、同様の関数が「文字列全体」に対して用意されています。たとえば isdigit()は「文字列全体が全て10進数ならTrue、否ならFalseを返す」関数として用意されています。

toupper()は、pythonでは関数名がupper()に変わりますが、その機能は「アルファベットの小文字は大文字に変換し(それ以外の文字は変換せずに)、処理後の文字列を返す」関数として用意されています。

str1 = "abc1"

length = len(str1)

for i in range(length):

if (str1[i].isdigit() == True):

print("Digit! at index:%d" % i)

else:

convStr = str1[i].upper()

if (convStr == "A")

print("Matched! at index:%d" % i)

「クラス」と「メンバ関数」について

上記のソースにおいて、関数isdigit および 関数upperは、関数lenとは異なり、文字列型の変数str1の「変数名の後にピリオド’.’を付けて」その後に関数名を指定して呼び出しています。その理由は、関数isdigit および 関数upperは、文字列型の「クラス」に属する「メンバ関数」として実装されているためです。

C++やJava等、クラスが使えるプログラミング言語の経験のある方々にとっては、馴染みのあるこの「メンバ関数」ですが、この種の(オブジェクト指向の)プログラミング言語のご経験の無いC言語プログラマの方々にとっては、馴染みの薄い事柄だと思います。

ここで少しだけ「クラス」および「メンバ関数」について補足します。

  • 「クラス」は、C言語における「構造体」に似ていますが、メンバとして「関数」が追加できます。
  • メンバとして追加した関数を「メンバ関数」と呼びます。
  • 「メンバ関数」では、(一般的には)他の「メンバ変数」の参照/変更に関わる処理を行います。

python において、どのような関数が関数lenのよう(グローバル関数のよう)に提供され、またどのような関数が「メンバ関数」として提供されているかは「こんな関数を使いたい」という「目的」が生じた時点で、ネット検索で確認してください。

配列(pythonでは「リスト」と呼びます)

pythonにおいても(C言語と同様に)配列が使用できます。pythonでは配列のことを「リスト」と呼びます。以下、リストの使用例を示します。

arr1 = [0,1,2]      # リストを初期化

print(arr1)        # [0, 1, 2] が表示される

arr1[1] = 100       # 1番目の要素を変更(インデックスはゼロ始まり)

print(arr1)        # [0, 100, 2] が表示される

arr2 = arr1        # リストを別の変数にコピー ⇒中身では無く「参照」がコピーされ、同じ実体を指す

arr2[1] = 11       # コピー先の1番目の値を書き換えた後、以下でコピー元のリストを表示

print(arr1)        # [0, 11, 2] が表示される(「参照」のコピー故、コピー元のリストも変化)

arr1.clear()       # メンバ関数clearで全データを消去

print(arr1)        # [] が表示される

arr1.append(101)     # メンバ関数appendでデータを追加

print(arr1)        # [101] が表示される

def func(arr, dt):    # 引数arrでリストの「参照」を受け、引数dtで設定する値を受ける

arr[0] = dt      # 0番目の要素を書き換え

func(arr1, 200)      # 上記関数を呼び出す

print(arr1)        # [200] が表示される

あるリストを別のリストに「代入」すると、中身が「コピー」されるのでは無く「参照」がコピーされます。すなわち「代入」した後は、コピー先、コピー元 共に、同じ「実体」を指すようになります。この特徴は「代入」だけで無く、「関数の引数」にリストを渡したときも同じです。

なお、この「参照」では無く、リストの中身をコピーしたいときもあると思います。この場合は、以下のように記述することで、「参照」では無く「中身がコピー」されます。

arr2 = []        #空のリストで初期化

arr2 += arr1      #そこに既存のリストarr1 の中身を追加(まとめて arr2 = [] + arr1 と書いても可)

ポインタ

pythonでは「ポインタ」は使えません。またJavaのような「参照」も、前節でご紹介した「リスト」等、一部の型でしか使えません。ですので、関数の引数に「整数型」や「文字列型」の変数アドレスを渡して、関数内で中身を「書き換える」こともできません。

この対策として、筆者は関数から「複数の戻り値」を返して、元の変数に「代入」する事で対処しています。

def proc(a, b, c):

b = a + b

c = b + c

a = c + a

return (a, b, c)


var1 = 1

var2 = 2

var3 = 3

var1, var2, var3 = proc(var1, var2, var3)

文字列のコピー

C言語では、strcpyやmemcpyを使って、文字列の中身をコピーしましたが、pythonでは「代入」によって文字列を「丸ごと」コピーできます。

str1 = "ABC"

str2 = str1

str2 = "012"

print(str1)        # ABC が表示される

print(str2)        # 012 が表示される

文字列は、一見するとC言語の配列のように見えますが、実は、文字列は「文字列(str)型」であり、リストとは異なり、「文字列中の一部の文字だけ書き換える」事はできません。たとえば以下は禁止されます。

str1 = "ABC"

str1[1] = 'b'

このような場合は、後節で説明する「スライス」を使って新たな文字列を作成し、その新たに作成した文字列「全体」をコピーし直します。

newStr = str1[0:1] + "b" + str1[2:]

str1 = newStr

スライス

先のpythonのソースコード中の[]は「スライス」と呼ばれ、文字列や配列(pythonでは配列のことを「リスト」といいます)の「一部を取り出す」ために使用します。書き方は以下です。

配列[開始位置:終了位置]

  • 開始位置は、先頭を「ゼロ番目」とするインデックス番号で指定します。
  • 終了位置も先頭を「ゼロ番目」とするインデックス番号で指定しますが、注意点として「終了位置より1つ大きい位置を指定する」必要があります。
  • たとえば文字列”ABC”が格納された変数str1の先頭2文字分を別物の文字列として取り出したい場合は str1[0:2] と指定します。

  • 開始位置、終了位置、共に省略できます。
  • 開始位置を省略した場合は、ゼロが指定されたと見なされます。終了位置を省略した場合は最後、すなわち最終位置より1つ大きい位置が指定されたと見なされます。

  • コロン’:’と終了位置を省略し、開始位置だけ指定することも可能です。
  • この場合は開始位置から1つ分の要素だけ指定したと見なされます。

(補足)

以前の節でご紹介したとおり、文字列の場合は「別物の文字列」が生成され、またリストの場合は「参照」が取り出されます。リストの場合は、スライスで取り出した一部の中身を「書き換える」ことが可能です。

list1 = [0,1,2,3]

list1[1] = 101          #書き換え可能

list1[2:] = [102,103]      #書き換え可能

for文

先のpythonのソースコード中の「for i in range(length):」は、C言語における「for (int i = 0; i < length; i++) {」に相当する記述でした。 pythonにおけるfor文では「for 変数名 in」の後に「配列」「リスト」等の「データの集合」を指定します。 たとえば先のpythonのソースコードは、文字列の先頭から1文字ずつ、別物の(1文字から成る)文字列として、スライスを使って取り出していましたが、これと同じ処理は、以下のように記述できます。

for chStr in str1:            # 文字列str1の先頭から1つずつ要素を取り出す

if (chStr == “A”):

ただこの方法では「何番目か」を」示すインデックス番号が取得できないです。このような用途に対して、pythonでは、以下の記述も使えます。

for i, chStr in enumerate(str1):    # 文字列str1の先頭から1つずつ要素を取り出す

if (chStr == "A"):

print("Matched! at index:%d" % i)

range()

本節では先のpythonのソースコードのfor文で使用した「range()」について説明します。rangeは「range型(クラス)」で、range()は「range型のオブジェクトの実体を生成して返す」関数です。
range型は、引数で指定した値に応じて、連続した値を要素として持つデータ集合です。たとえば「range(3)」として指定すると、この関数は「0,1,2」の連続する3つの値を持つオブジェクトを返します。

rangeは、for文以外ではあまり使う事が無いと思いますので、rangeについての説明は、この程度に留めます。この説明をご覧になられて混乱された方は、慣れるまで rangeは、上記したpythonソースの例のように「for文でしか使わない」と割り切って使って頂いて大丈夫と思います。

書式変換

C言語では、printf文において”%d” や “%x” 等の書式変換が使用できますが、pythonでも、基本、同様の書式変換が可能です。

書式付き文字列 % (引数1, 引数2, 以降も続く)

引数が1つの場合は、 書式付き文字列 % 引数1として記述し、%の後の括弧()は不要です。pythonでは、上記の書式変換は、print関数に限らず「文字列に対する操作」として使用できます。よって前の節に記述したpythonの画面表示のソースコードは、以下のように書き換える事も可能です。

resultStr = "Hit at index:%d" % i

print(resultStr)


(補足)関数printは、C言語のprintfに相当する画面表示関数です。

ソースファイルの実行方法

  • pythonのソースファイルの拡張子は.pyです。この拡張子でソースファイルを作成してください。
  • pythonのソースファイルは事前にコンパイルする必要は無く、いきなり、DOSプロンプト上で「python ソースファイル名.py」で実行できます。
  • pythonのソースファイル実行時、言語仕様 他に違反したコード記述を実行した場合、「例外」が発生し、実行が途中終了します。
  • その際、「例外」に至るまでの「関数呼び出し」の履歴と、エラー内容が画面表示されます。

その他の言語仕様について

以上、第1回の講座では、pythonの言語仕様について、C言語と比較する形で簡単にご紹介しました。
実際にpythonでプログラムを作成する上では、上記以外にも、知っておいた方が良い事柄が沢山あります。以下では思い付いた事柄を列挙します。詳細については、ネット検索でご確認ください。

  • 日本語の文字エンコードは、デフォルトはUFT-8。これをシフトJISに変更したい場合は、ソースファイル先頭にコメントとして、以下を記述すれば良いです。

# -*- coding: sjis -*-

  • pythonではfor文以外にも、if文、elif文、else文、while文 の制御文が使用できます。
  • switch~case文に相当する制御文として、Pythonの3.10以降ではmatch~case文が使用できるようになりました。
  • ただ古いpythonでも実行できるソースコードを書くならmatch~case文は使わずに、if,elif,else文を並べて、同じ変数値を繰り返し比較する必要があります。

  • 関数の先頭行や、if文、elif文、else文、while文 の末尾には、コロン(:)が必要です。
  • これを忘れると、実行時にエラー表示され、実行できません。

  • ループ文のブロック内では、continue文、break文が使用できます。
  • ブール値(true/false)には、大文字から始まる True、False が使用できます。
  • C言語の && || は、and or と記述する必要があります。
  • インクリメント、デクリメントは使用できません。代替として、+= や -= を使用します。
  • #define は使えません。代替としては、大文字で変数を宣言し、通常の変数のように初期化して使用する記述が良く使われます。
  • #ifも使えません。筆者は代替として通常のif文を使っています。例:「#if 0」は「if (False)」等
  • 豊富なライブラリが用意されています。pythonのインストール時にインストールされなかったライブラリは、DOSプロンプト上で実行する「pip」コマンドでいつでも追加でインストールできます。
  • 「こんなライブラリが欲しい」と思われた時点で、ネット検索で確認してください。お目当てのライブラリが見つかると思います。