開発言語 Python(その14)

【連載】

にわか管理者のためのLinux運用入門

【第175回】開発言語 Python(その14)

[2019/04/23 10:05]後藤大地 ブックマーク ブックマーク

サーバ/ストレージ

Pythonとオブジェクト指向

前回までの説明で、Pythonを実際のツールとして活用するのに必要となる基本的な知識はだいたい伝えられたと思う。後は、デフォルトで用意されている機能を実際にはどう使うのかを理解しておけば、随時検索エンジンなどでTipsやQ&Aを調べていくことである程度のことはできるようになるだろう。

そのため、取り上げるべきかどうか迷うところではあるのだが、「The Python Tutorial」では次の解説対象として「クラス」を挙げているので、ここでも読める程度にクラスの機能を紹介しておこう。

Pythonそのものはオブジェクト指向プログラミングに必要となる機能を一通り提供していると言われており、いわゆるオブジェクト指向プログラミング言語ということになる。しかし、これまでにも説明してきたように、Pythonはオブジェクト指向を意識しなくても利用できる仕組みになっている。ツールとして手軽に使っていきたい場合、クラスの機能はコーディングや考え方をちょっとばかり複雑なものにするので、本連載ではあまり深入りしたくなかったりもする。

The Python Tutorial」のクラスの説明を読んでもらえればわかると思うが、概念やスコープの説明が結構ややこしい。ほかのプログラミング言語でオブジェクト指向プログラミングの経験があるなら、この部分の説明は”よくあるオブジェクト指向プログラミングの説明”だということがわかるかもしれない。しかし、そうでない場合、ちょっとばかり頭が痛くなるところではないかと思う。

本連載では、「ツールとしてPythonを使って楽をする」というところに主眼を置いているので、こういう書き方ができる、という程度に知っておいていただきたい。無論、説明を読み解くのが特に苦ではないなら、Pythonでバリバリのオブジェクト指向プログラミングをしてもらってよいと思う。

クラス

Pythonでは「class」というキーワードを使って、クラスを次のように定義する。サンプルでは「MyClass」がクラス名、「i」がクラス変数、「f()」がメソッドということになる。

>>> class MyClass:
...     """A simple example class"""
...     i = 12345
...     
...     def f(self):
...         return 'hello world'
... 
>>>

オブジェクトの生成と、クラス変数とメソッドへのアクセス方法は次のようになる。

>>> x = MyClass()
>>> x.i
12345
>>> x.f
<bound method MyClass.f of <__main__.MyClass object at 0x7f87f9faa198>>
>>> x.f()
'hello world'
>>>

次はコンストラクタだ。Pythonではオブジェクトを生成する段階で処理を行わせることができ、その処理はコンストラクタが担う。Pythonでは「__init__()」がコンストラクタとされており、次のような感じで使用する。

>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
... 
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)
>>>

コンストラクタの存在理由だが、その必要性はクラス変数とインスタンス変数の違いがわかるようになるとわかりやすくなる。まず、次のサンプルを見てほしい。

>>> class Dog:
...     kind = 'canine'         # class variable shared by all instances
...     
...     def __init__(self, name):
...         self.name = name    # instance variable unique to each instance
... 
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind                  # shared by all dogs
'canine'
>>> e.kind                  # shared by all dogs
'canine'
>>> d.name                  # unique to d
'Fido'
>>> e.name                  # unique to e
'Buddy'
>>>

上記サンプルでは「kind」と「name」という2つの変数があることがわかる。kindはクラス変数と呼ばれ、nameはインスタンス変数と呼ばれる。kindはクラスから生成されるすべてのオブジェクト(インスタンス)で共有される。逆に、コンストラクタで生成されるnameはオブジェクト(インスタンス)ごとに用意されており、共有はされない。

つまり、インスタンス変数として値を保持させたい場合には、コンストラクタに引数として値を与えるといった使い方になる。

クラス変数とインスタンス変数の違いを示す次のサンプルを見てみよう。このサンプルでは、add_trick()メソッドが呼ばれると、クラス変数であるtricksに対して値が追加される。このため、2つの異なるオブジェクトからadd_trick()メソッドをコールした結果、共有されているtricksクラス変数に値がアペンドされたことがわかる。

>>> class Dog:
...     tricks = []             # mistaken use of a class variable
...     
...     def __init__(self, name):
...         self.name = name
...     
...     def add_trick(self, trick):
...         self.tricks.append(trick)
... 
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks                # unexpectedly shared by all dogs
['roll over', 'play dead']
>>>

次のサンプルはインスタンス変数の使用サンプルだ。add_trick()メソッドはインスタンス変数に対してアペンドを行っている。インスタンス変数はオブジェクトごとに保持されるため、add_trick()をコールしてもほかのオブジェクトには影響が及んでいないことがわかる。

>>> class Dog:
...     def __init__(self, name):
...         self.name = name
...         self.tricks = []    # creates a new empty list for each dog
...     
...     def add_trick(self, trick):
...         self.tricks.append(trick)
... 
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']
>>>

次のサンプルはクラスを使った応用例だ。for制御構文にそのまま指定できるオブジェクトを作るために、__iter__()と__next()__というメソッドが実装され、求められる仕様を満たしている。このように必要なメソッドが実装されていれば、要求される動作を満たすことができる。

>>> class Reverse:
...     """Iterator for looping over a sequence backwards."""
...     def __init__(self, data):
...         self.data = data
...         self.index = len(data)
...     
...     def __iter__(self):
...         return self
...     
...     def __next__(self):
...         if self.index == 0:
...             raise StopIteration
...         self.index = self.index - 1
...         return self.data[self.index]
... 
>>> 
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x7f87f9faa908>
>>> for char in rev:
...     print(char)
... 
m
a
p
s
>>>

Pythonのクラスに関しては最低限、この辺りを理解しておけばよいだろう。

処理やデータをまとめておく

お手軽ツールとしてPythonを使っていく場合には、クラスをオブジェクト指向的に考えるというよりは、データや処理を(関数を)まとめていくためのデータ構造の1つ、くらいに考えておけばよいと思う。似たような意味合いを持つデータと関数をまとめておいたほうがいいな、と思い始めたらクラスとして整理する、くらいの感じでよいだろう。

もちろんオブジェクト指向で考えを整理することに慣れているなら、最初からその方法でPythonを使っていく方向でよいと思う。好きなら使い、よくわからないなら使わない。ツールとしてPythonを使うという観点から言えば、クラスについてはそんなスタンスでよいのではないだろうか。

【参考資料】
The Python Tutorial

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

一覧はこちら

連載目次

もっと知りたい!こちらもオススメ

なぜ今、統合システムなのか? 押さえておくべき「3つのインパクト」

なぜ今、統合システムなのか? 押さえておくべき「3つのインパクト」

ガートナー ジャパンは10月31日~11月2日、都内で「Gartner Symposium/ITxpo 2017」を開催。11月1日には同社 主席アナリストの青山浩子氏が登壇し「CIOが理解すべき統合システムの3大インパクト」と題する講演を行った。本稿では、講演の内容をダイジェストでお届けする。

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で IT Search+ の人気記事をお届けします

会員登録(無料)

注目の特集/連載
[解説動画] Googleアナリティクス分析&活用講座 - Webサイト改善の正しい考え方
知りたい! カナコさん 皆で話そうAIのコト
教えてカナコさん! これならわかるAI入門
対話システムをつくろう! Python超入門
Kubernetes入門
AWSで作るクラウドネイティブアプリケーションの基本
ソフトウェア開発自動化入門
PowerShell Core入門
徹底研究! ハイブリッドクラウド
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

ページの先頭に戻る