LoginSignup
0
2

More than 1 year has passed since last update.

C系言語話者が学ぶPython入門

Last updated at Posted at 2023-03-30

筆者のプロフィール

専門学校時代にUnityを使ったゲーム開発や、C++の勉強をしていました。
タイトルにC系言語話者とはありますが、C系めちゃくちゃ詳しいっていうわけでもありません...
23卒でIT業界に内定をいただいて現在Pythonの研修をしており、その過程でC系の言語とPythonの違いでこんがらがって苦しんでいる最中です。
そのため、Qiitaに記事として残しておくことで後で見返して復習しやすい形にして備忘録のように使うつもりです。(随時追加予定)

Pythonとは

インタープリター型のプログラミング言語
何にでも幅広く使えるようで、「読みやすく効率のいいコードを簡単に書ける」という思想の元開発されているらしい。
オープンソースのライブラリがたくさん転がっていることも特徴。
(Wikipedia自己解釈)

PythonとC++の違い

型宣言がない

この型宣言に関する部分が何よりも大きいと感じる差異です。
C++はじめC系の言語では必ず変数などの宣言時に型宣言をし、その変数にはその型以外のデータを代入することは基本的にできません。(C++のテンプレートやC#のジェネリックを除く)
ですが、Pythonには型宣言がなく、変数はどんなデータでも代入できるものとなっているようです。

Python
a = 100
print(a)
a = "hoge"
print(a)

結果

100
hoge

こんな処理ができるわけです。
長らくC系の言語のみに触れてきた私にとってはまぁ慣れないですね~
使い込んでいけば行くほど使いやすくなりそうではあるんですけどね~

型が可変する変数はどれほどのメモリを消費してるのか気になるところではあるのですが、色々調べてみてもそれに関する記事を見つけることはできませんでした。

キャストの仕方

これは主にC#とPythonの違いになるのですが、キャストの際にカッコを付ける位置が違います。(細かい)

C#
string str = "12345";
int a = (int)12345;
python
num = 12345 
print(str(num))

と、このように型にカッコを付けるか、変数にカッコをつけるか程度の違いですが、これも慣れずによく型の方にカッコを付けてしまってエラーを吐いてしまいます...
また、Pythonではそもそも変数に型がないため、キャストを必要とする場面は限られてくるのですが、特に不便だと感じる点として、printで出力する際に整数型のままでは出力できないという点です。
おそらく変数だけでの出力なら可能なのでしょうが、文字列と一緒に出力する際には文字列型にキャストをしてあげないとだめです。

スコープの扱い

これが個人的には一番苦しいです!!
C系の言語では、スコープの範囲を{}で指定していたと思います。
例えばifでしたら

C++
if(a == b){
    a++;
}
std::cout<< a <<std::endl;

といった感じに、スコープの範囲を指定し、{}の範囲内ならインデントは自由にできていました。(綺麗なコードにはならないだろうけど...)
しかし、Pythonではそのインデントでスコープの範囲を指定するのである。

python
if a == b :
    a+=1
print(str(a))

となるのです。
これだけ見ればコードが簡潔になって見やすいように感じるかもしれませんが、これが、長いコードになってくるとマジで見にくくなってきます。
これも慣れるしかないのでしょうね...
もしVScodeでその辺をC系チックにできる拡張があれば教えて...

for,if,whileなど

この辺りの書き方は、かっこがなかったり、コロン(:)が必要だったり(switch/case文のcaseみたいな感じになる)と、結構違ってきてます。
特に違うのはfor文でしょうか。
C系では純粋にループ処理として使っていたであろうfor文ですが、Pythonでは配列の中身を順に変数に代入して処理をしていくという、C++で言う所の範囲forであったり、C#のforeachがデフォルトのfor文となっています。(もちろん、普通にループ処理だけをするために、for文を使うこともできますが、別途rangeという関数が必要)

C++のfor文
for(int i=0;i<10;i++){
    a++;
}
pythonのfor文
#前提として配列が必要
box = ["apple","orange","grape"]
for item in box :
    print(item)
C系言語に近いpythonのfor文
for index in range(5) :
    print(str(index))  #0,1,2,3,4と出力される
switch文がない!!

これ、甚大です。
ですが、どうやらPython3.10でC系のswitch文にあたるパターンマッチという機能が追加されたようです。
前情報でさんざんPythonはswitch文がない!!と言われ続けてきたため、ちょっと安心しました。(C系ユーザーの中にはelse ifを使うぐらいならswitchを使う!っていう人も結構いますからね...)

python
num = 100;
match num:
    case 0:
        print("no!")
    case 100:
        print("yes!!")
    case _:
        print("error") #_はワイルドカードとしてdefaltのように扱う

クラスに関するあれやこれ

インスタンス変数

メンバ変数インスタンス変数と呼ばれているっぽい?
ただ、インスタンス変数の宣言が気持ち悪い形で出来るようになっており、私が使っている教材でもその手段がとられており衝撃を受けた(それがスタンダードなのかは不明)

Python
class Animal:
    pass #passはこの時点では何もしないという宣言(これをしないとエラーが出るっぽい?)

cat = Animal()
cat.cry = "meow"

print(cat.cry) #meowが出力される

これやばくないですか?鳥肌が立つレベルで気持ち悪い処理だと感じてしまいました...

インスタンスメソッド

メンバ関数のことはどうやらインスタンスメソッドと呼ばれている模様(?)
これもC系とは違う部分が多いですね...

C++
class Animal {
public:
    void cry(string name) {
        std::cout << "meow" << std::endl;
    }
};

int main() {
    Animal cat;
    cat.cry(cat);
}
Python
class Animal():
    name = "anyAnimal"
    def cry(self):   #selfには関数を呼び出したオブジェクトが入る(必須)
        print(self.name+" meow")

cat = Animal()
cat.name = "cat"
cat.cry()   #関数呼び出し時にselfは渡してあげる必要はない
出力結果
cat meow

ぱっと見で目立つのはやはりselfの存在ですね。
これはインスタンスメソッドを使用する際には必須の引数となり、文言もselfでないとだめなようです。
そして、このselfどんな意味があるのかというと、そのインスタンスメソッドを呼び出したインスタンスを自動的に渡すという効果があります。
このselfを使えば、上記のプログラムのように、self.nameと呼び出した自身のインスタンス変数にアクセスというようなこともできるようになります。
これは便利ですね!!
ちなみに、self以外の引数を使いたい場合は、def cry(self,volume)という風に第2引数以降に書いていき、cat.cry(small)というように、呼び出し側からは第1引数から渡してあげる事で引数を利用できます。

ファイル分け

C++と同じ要領でできるっぽい?ヘッダやソースファイルという分け方ではなさそう
分けたファイルを読み込むときは、import ファイル名と宣言する。
便利な機能として、別のファイルのクラスだけ読み込むことができる。

main.py
from base_animal import Animal

cat Animal
cat.cry
base_animal.py
class Animal():
    name = "anyAnimal"
    def cry(self):  
        print(self.name+" meow")

このように、ファイルの中から一部のクラスだけをインポートすることができるみたいです!これ便利!

継承

継承もほぼ一緒です。書き方が違う程度

cat.py
from animal import Animal

class Cat(Animal):
    pass

cat = Cat()
cat.cry()
animal.py
class Animal():
    def cry(self):
        print("meow")
出力結果
meow

もちろん派生クラスで新しくインスタンスメソッド、変数を宣言することも可能。

オーバーライド

オーバーライド自体は特別な処理をしなくてもC++と同様にできるようです。
ちなみに、仮想関数は標準機能には搭載されておらず、有志の外部ライブラリを使用しないと使えない模様。
それとは別に、特殊な仕様として、super()というものがあります。
C系の言語では恐らくできなかった親クラスの関数を呼び出して使用するということができてしまいます。(ここで出てくる__init__については下の方に書いてあります。)

animal.py
class Animal:
    def __init__(self,name,speed):
        self.name = name
        self.speed = apeed
cat.py
from animal import Animal

class Cat(Animal):
    def __init__(self,name,speed,cutePower):
        super().__init__(name,speed)   #これで、親クラスのコンストラクタにあたる関数を呼び出して、自身の引数を渡し、実行することができる
        self.cutePower = cutePower
        print(self.name + ": 速さ=" + str(self.speed) + ",可愛さ=" +str(self.cutePower))
main.py
from cat import Cat

cat = Cat("キキ",10,255)
出力結果
キキ: 速さ=10,可愛さ=255

これは便利そう!!C++にも実装してくれ!!(もうあったら教えて)

細かい差異

関数まわり

C系では型宣言 関数名(引数){処理内容}でしたが、
Pythonではdef 関数名(引数) 処理内容となる

コンストラクタ

C++ではクラスと同名のメンバ関数を用意することで出来ていたコンストラクタですが、Pythonではコンストラクタ専用の__init__という関数が用意されているようです。

Python
class Animal():
    def __init__(self):
        print("動物クラスです")

cat = Animal()
出力結果
動物クラスです

と、C++のコンストラクタと使い方自体は同じですね~
引数付きコンストラクタも同様の方法で使用できます。

締め

チュートリアルをやってみただけでも、こんなに違いが出てくるわけですから、なかなか習得は難しいな~と思います。
Pythonの方が便利だと感じる部分もあれば、C系の方が便利だと感じることもたくさんありますね。ですが、それ自体は新しい言語を習得するうえで越えなければならない壁だと思っているので、時間をかけて慣れていくのがいいのかなって思ってます。
個人的にPythonで一番嫌だと感じるのは、インスタンスからクラスのメンバ変数を追加できるところですね~ これがスタンダードじゃなければいいんですけど...

この記事は随時更新していく予定なので、何かあればコメントによろしくお願いします。

0
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2