C#プログラマからみたPython クラス(基本)編

オブジェクト指向の基本的な概念については割愛。

クラスの宣言とインスタンス

# python
#1番簡単なクラスの例
class MyClass:
    # passは「なにもしない」ことを意味する
    pass

#インスタンス化
i = MyClass()
// C#
class MyClass
{
}

var i = new MyClass();

クラスの宣言自体はあまり変わらないが、インスタンス化する時に、PythonC#では全く異なる。

Pythonでは変数の前の型の宣言はないことに加え、「new」のようなキーワードもないので、非常に短くなっている。
new」がないことによりコードは短くなっているが、関数の結果を格納するのか、インスタンス化しているのかぱっと見で判断できない…(´・ω・`) 個人的にはこれはやり過ぎな気もする。

端折ったアクセス修飾子については、後述のカプセル化を参照


アトリビュート

型に厳しいC#にはない概念。 インスタンスにデータを持たせたい時にアトリビュートを利用する。
変数宣言などと同じく、アトリビュートについても代入を行うことで定義する。

#インスタンス化
i = MyClass()

i.value = 5
print(i.value)

i.hoge = '( ー`дー´)キリッ'
print(i.hoge)

このようにアトリビュートに代入を行うだけで、インスタンスアトリビュートをいくつも追加することが出来る。
ただし、C#のクラス変数とは異なり、アトリビュートが追加されるのは実際に代入を行ったインスタンスにしか追加されない。

クラス自体に手をいれること無くクラスを拡張できるので、非常に強力で便利だとは思うが、C#のようなカタい言語をやってきた身からすると、アトリビュートはクラス宣言(の内容)と関係なく利用できてしまうので危険な香りが……。


初期化メソッド

Pythonにはインスタンス生成時に呼ばれるメソッドを定義することができる(※)

class MyClass:
    def __init__(self):
        self.value = 0
        print('初期化メソッドが呼ばれました')

i2 = MyClass()
print(i2.value)

Pythonの場合、この初期化メソッドを利用してクラス(インスタンス)にどのようなデータをもたせるかを決めることができる。

初期化メソッドの引数は「self」以外の引数を設定することができるので、インスタンスを初期化する時に引数を経由して、インスタンスのデータの内容をコントロールすることが可能。
(詳細とサンプルは後述…)

なお、PythonにはC#のクラス変数のような仕組みはなく、 (C#でいうところの)クラス変数を利用したい場合は、常にアトリビュートに対して代入を行う必要がある。

インスタンス生成時に呼ばれるメソッドというとコンストラクタを思い浮かべますが、あくまで初期化処理であり、コンストラクタとは異なるようです。 → そのうち追記予定。


self

クラスを定義したら「__init__()」と同様に、第一引数に「self」を必ず渡すようにする。

class Prism(object):
    def __init__(self, width, height, depth):
            self.width = width
            self.height = height
            self.depth = depth

    def content(self):
        return self.width * self.height * self.depth

#Prismクラスを利用する。
#クラスを利用するときには、selfに対して引数を指定していないことに注意する。
p1 = Prism(10,20,30)
print(p1.content())

つまり、「self」とは自分自信のインスタンスを示しており、クラス定義の中でインスタンスに対して操作を行いたい時は、かならず「self」という引数に対して処理を行う。
C#のthisと似たようなもの? ちょっと理解が足りてないので後で調べる

なお、第一引数の名前は習慣的にselfとなっていおり、文法的にはただの引数なので、thisでもmeでも良い。
とは言え可読性を損なうためselfを使うようにする。


カプセル化

前提として基本的にPythonのクラスやメソッドはPublic扱いとなる。
Privateに利用したい場合は、「_(アンダースコア)」を利用してカプセル化を行う。

アンダースコア1つ

例)
_size

ただの習慣、紳士協定。利用者側から観た時に、「あー、この関数は使ってほしくないんだなー」と思わせる為に利用するもの。習慣を知らなかったり、紳士じゃない場合には無力。

アンダースコア2つ

例)
__size

こうしておくと、クラスの外部からは「__size」という名前でアクセスできなくなる。利用する側から見るとC#などのPrivateに近い。
ただし、実態としては名前が内部的に他の名前に置き換わっているだけ! どのように名前が置き換わるか把握していれば、アクセスすることは可能。

C#などに比べてカプセル化の機能がかなりユルイ。。。
C#が「おめーらほっとくと何するかわかんねーから、Privateは絶対触れないようにしとくから!」と言われているのに対し、Pythonは「オレの知ってるオメーらはそこまでアホじゃないから、Privateの制約がこの程度でもちゃんとできるよな?」と言われているような感じ。