LPIC201 勉強記録 1日目~


infrastructure-tech.hatenablog.com

1日目~

1日目

スピードマスター

1章(1-12):正答率66%

2日目

スピードマスター

1章(誤答のみ):正答率100%

2章(1-8):正答率25%

1章は基礎的なコマンドなのでまだ良い。

2章はLinuxカーネルに入るのでイメージし辛く全く興味がないのでしんどい…

3日目(2/22)

スピードマスター

1章(誤答のみ):正答率100%

2章(1-16):正答率85%

4日目(2/24)

スピードマスター

2章(誤答&16-30):正答率52%

2章ひとまず完了!ここまででLPIC0201範囲の20%になります。

 

LPIC2取得に向けて

動機

LPIC1はギリギリ取得できていたので、職場での次の目標としてLPIC2を宣言してしまったため

LPIC系の資格は今まで受験した資格の中で一番勉強が辛いです…

特に最初の方のシステムアーキテクチャの部分はWindowsで慣れていると意識する必要がない部分なのでイメージし辛く、そうそう実務で使う分野でもなく、これを覚える意味があるのかと思うほど面白くない(※個人の感想です)ので全く勉強のモチベーションも沸かず、なかなか手が進まないです。

が、頑張ろうと思います。

参考書・勉強方法など

今後変更する可能性もありますが、現時点で利用しようと思っているものを記載しておきます。

Ping-t

LPIC1でも利用した

問題量が豊富な反面多すぎるため精査が必要だと思う

スピードマスター LPIC2

いわゆる白本

似た問題が出題されるということでメルカリで購入

ToggleTrack

様々な時間の記録に利用している為、今回も活用してみる

iPad&GoodNotes 5

紙のノートを増やしたくないのでiPadを利用(ただピンポイントで見返したいときは紙の方が早かったり…)

つるつる滑るのに慣れずちょっと書きにくいので改善したい

スプレッドシート

参考書に書き込むのが好きではないので回答結果をスプレッドシートでまとめる

正答率や過去との推移を確認しやすいが、直接書き込んだほうが勉強のハードルは下がる気はしている

 

オブジェクト指向のポリモーフィズムとは

先にクラスの記事を読んでおくことをお勧めします。 infrastructure-tech.hatenablog.com

ポリモーフィズムとは

プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。ポリモルフィズム多態性、多相性、多様性とも呼ばれる。

難しいですね。
ざっくり言うとサブルーチンの真逆の動きをすることです。
サブルーチンの場合、サブルーチン(呼び出される側)は複数のメインルーチン(呼び出す側)に共通でした。
ポリモーフィズムの場合、メインルーチン(呼び出す側)は複数のサブルーチン(呼び出される側に)に共通です。 それぞれの共通ルーチンは、対応するルーチンが増えても修正する必要がありません

ポリモーフィズムについて解説しているサイトでは、サンプルコードに抽象クラスや継承を利用していることが多いですが、継承の利用は必須ではないと思います*1 ただ、ポリモーフィズムを実現には継承が効率的なため、広く利用されているのかと思います。

メインルーチン サブルーチン
サブルーチン 複数 共通
ポリモーフィズム 共通 複数

良く上げられる例が動物の例えです。 クラスの記事でも例えましたが、犬や猫は動物クラスにいます。
動物に対して「鳴け」と指示すると、犬ならば「ワン」猫ならば「にゃー」と鳴き、対象の動物によって動作が異なります。

ただこの例えは分かりやすい反面、クラスと同じように混乱を招く要因だと思います。
なぜなら私たちは動物に対して「鳴け」と指示することができないからです。
犬や猫など(具現化された)特定の動物に対して訓練し指示すること はできますが、「動物」のように抽象化された概念に指示することはありません。

そこで今回は実際に利用しているstr関数で考えてみましょう。
何気なく使っているstr関数ですが、よく考えると様々な型であってもString型に変換してくれています。

num_i = 100,
num_f = 10.5
array =['A','B','C']
handan = True

print(type(num_i),type(num_f),type(array),type(handan))
#変換前
#<class 'tuple'> <class 'float'> <class 'list'> <class 'bool'>
a =str(num_i)
b =str(num_f)
c =str(array)
d =str(handan)

print(type(a),type(b),type(c),type(d))
#変換後
#<class 'str'> <class 'str'> <class 'str'> <class 'str'>

strというメインルーチンは共通で、各サブルーチンの処理の中身を意識する必要がありません。
ポリモーフィズムの動作イメージが付いたでしょうか?

コード例(抽象クラス・継承無し)

実際にプログラムしながら理解を深めていきます。
まず継承を使わないバージョンのコードです。

class aircon():
    def on(self):
        print('【エアコン】<ON')
    def off(self):
        print('【エアコン】<OFF')

class fan():
    def on(self):
        print('【扇風機】<ON')
    def off(self):
        print('【扇風機】<OFF') 

machine = aircon()
machine.on()
machine.off()
#【エアコン】<ON
#【エアコン】<OFF

machine = fan()
machine.on()
machine.off()
#【扇風機】<ON
#【扇風機】<OFF

machine.on()machine.off()と同じon/offメソッドを実行していますが、machineに対して与えたオブジェクトによって出力結果が異なることが分かります。
machine = aircon()の時はエアコンが操作され、machine = fan()の時は扇風機が操作されています。
ただしmachineでは何のオブジェクトが入っているかを気にする必要がありません これでも動きとしてはポリモーフィズムと言えると思います。
が、オブジェクト指向で散々言われている「抽象化」「概念」は?と思うと思いますので、次に継承を用いた例を考えてみます。

コード例(抽象クラス・継承有り)

続いて抽象クラスを継承したバージョンです。
何やらimportして、新しくsignalクラスが作られていることが分かります。

ちなみにfrom abc import ABCMeta, abstractmethodは「from モジュール名 import クラス名」の意味があります。
import abcの場合abc.@abstractmethodとモジュール名も記載する必要がありますが、fromを使うことでクラス名を直接使うことができます。

from abc import ABCMeta, abstractmethod #抽象基底クラスをインポート
class signal(metaclass = ABCMeta): #signalクラスを作成
    @abstractmethod #各メソッドにデコレータ@abstractmethodを付与
    def on(self): #メソッド
        pass
    @abstractmethod
    def off(self):
        pass

class aircon(signal):   #signalクラスを継承
    def on(self):
        print('【エアコン】<ON')
    def off(self):
        print('【エアコン】<OFF')

class fan(signal):
    def on(self):
        print('【扇風機】<ON')
    def off(self):
        print('【扇風機】<OFF')  

machine = aircon()
machine.on()
machine.off()
#【エアコン】<ON
#【エアコン】<OFF

machine = fan()
machine.on()
machine.off()
#【扇風機】<ON
#【扇風機】<OFF

まずfrom abc import ABCMeta, abstractmethodで抽象基底クラスであるabcから、「ABCMeta」と「abstractmethod」を呼び出しています。 なおPython3.4以降の機能のようです。 詳細は以下のサイトにありますが、「ABC」を継承することでも同じ動きが実現できます。

from abc import ABC
class MyABC(ABC):
    pass

docs.python.org

動きを解説するまえに、今出てきた単語の意味を解説します。

abc.ABCMeta

抽象基底クラス(ABC)を定義するためのメタクラス

抽象クラスとは

抽象クラスは、クラスのメタクラスにabc.ABCMetaを設定することで実装可能です。
動物の例えは理解しづらいと思うため、今回はリモコンを例にして考えていきます。

「エアコンのリモコン」と「扇風機のリモコン」は別々の動きをしますが、2つのリモコンには共通点もあります。
それは「ON」や「OFF」の機能があるという点です。
そこで抽象化をし、「リモコン」という概念を作り出します。
この段階で以下の状態になります。

信号を出すリモコン > エアコンのリモコン > ON/OFF機能、冷房、暖房
          > 扇風機のリモコン  > ON/OFF機能、風量、首振り
↓抽象化
信号を出すリモコン > ON/OFF機能

この抽象化されたリモコンが、抽象クラスであるsignalにあたります。

class signal(metaclass = ABCMeta):
    @abstractmethod
    def on(self):
        pass
    @abstractmethod
    def off(self):
        pass

メタクラスとは

メタクラスとはインスタンスがクラスとなるクラスのことである。通常のクラスがそのインスタンスの振る舞いを定義するように、メタクラスはそのインスタンスであるクラスを、そして更にそのクラスのインスタンスの振る舞いを定義する。

難解な文章ですね。順番に理解していきましょう。

メタクラスとはインスタンスがクラスとなるクラスのことである。

クラスからインスタンスを生成するように、メタクラスからクラスを生成できます。

②通常のクラスがそのインスタンスの振る舞いを定義するように

通常、クラスはインスタンスの振る舞いを定義しています。

メタクラスはそのインスタンスであるクラスを

同じようにメタクラスはクラスの振る舞いと、

④そして更にそのクラスのインスタンスの振る舞いを定義する。

クラスのインスタンスの振る舞いも定義しています。

ざっくり言うとメタクラス*2>クラス*3>インスタンスという流れになっています。

@abstractmethod

抽象メソッドを示すデコレータです。

デコレータとは

本題とは少し離れますが、ここでは簡単なデコレータの例を使って解説します。
デコレータを使うことで、関数の前後や戻りを修飾(Decorator)することができます。
デコレータは糖衣構文(syntax sugar)と呼ばれ、初心者には難しい構文も簡単に見せることができます。
*args, **kwargsは、デコレートする関数の引数を挿しています。

def decorator(func):  #デコレータの定義
    def cookie(*args, **kwargs):
        print('オ')
        func(*args, **kwargs)
        print('オ!')
    return cookie

@decorator  #デコレータ
def write():
    print('レ')

write()
#オ
#レ
#オ!

あら不思議「オレオ!」と出力されました。
なお@decoratorを付けないと、「レ」しか出力されません。

うーん横並びのほうが綺麗だな・・・と思った方は戻り値をデコレートしてみましょう。 decorator()とwrite()を変更しました。

def decorator(func):  #デコレータの定義
    def cookie(*args, **kwargs):
        result ="オ" + func(*args, **kwargs)+"オ!"  #文字列結合
        return result
    return cookie

@decorator  #デコレータ
def write():
    return 'レ'  #returnに変更
print(write())
#オレオ!

これで横並びに出力できました!
func(*args, **kwargs)の戻り値になっている「レ」が、デコレータによって「オ」と「オ!」が結合されています。
このように自由に関数を修飾できるのがデコレータです。
なお複数付けた場合はどうなるでしょうか。

def decorator(func):  #デコレータの定義
    def cookie(*args, **kwargs):
        print('オ')
        func(*args, **kwargs)
        print('オ!')
    return cookie
def decorator2(func):  #デコレータの定義
    def cream(*args, **kwargs):
        print('クリーム')
        func(*args, **kwargs)
        print('クリーム')
    return cream

@decorator  #デコレータ
@decorator2
def write():
    print('レ')

write()
#オ
#クリーム
#レ
#クリーム
#オ!

プログラムの上から処理されるイメージがあるとおもいますが、デコレータの場合関数に近いほうから処理されます。 「レ」をdecorator2でデコレートすると「クリーム レ クリーム」
「クリーム レ クリーム」をdecoratorでデコレートすると「オ クリーム レ クリーム オ!」になるという流れです。

@abstractmethodの役割

改めて@abstractmethodについて解説します。
このデコレータをメソッドにつけることで、明示的に抽象メソッドであることを示し、インスタンスでの実装を強制することができます。 先ほどのコードを元に解説していきます。

signalクラスのonメソッドに@abstractmethodが付与されています。 そしてsignalクラスを継承したairconクラスにも同じ名前のonメソッドがあります。

class signal(metaclass = ABCMeta): #signalクラスを作成
    @abstractmethod #各メソッドにデコレータ@abstractmethodを付与
    def on(self): #メソッド
        pass
~中略~
class aircon(signal):   #signalクラスを継承
    def on(self):
        print('【エアコン】<ON')

クラスのメソッド名誤り

airconクラスのメソッド名を誤入力し、「xxx」というメソッド名で作成したらどうなるでしょうか。

from abc import ABCMeta, abstractmethod
class signal(metaclass = ABCMeta):
    @abstractmethod
    def on(self):
        pass
~中略~
class aircon(signal):
    def xxx(self):
        print('【エアコン】<ON')
~中略~
machine = aircon()
#TypeError: Can't instantiate abstract class aircon with abstract methods on

aircon()をインスタンス化した段階で「 抽象メソッド "on "の抽象クラスairconをインスタンス化できない」とエラーが出ました。
これによりクラスのメソッド名が誤っていた場合に気づくことができます。

@abstractmethodを付与しない

ではsignal抽象クラスのonメソッドに「@abstractmethod」を付与しなかったらどうなるでしょうか。

from abc import ABCMeta, abstractmethod
class signal(metaclass = ABCMeta):
    def on(self):
        pass
~中略~
class aircon(signal): 
    def xxx(self):
        print('【エアコン】<ON')
~中略~
machine = aircon()
machine.xxx()
#【エアコン】<ON

問題無くインスタンス化し実行されました。
signal抽象クラスで「@abstractmethod」が付与されていないメソッドの実装は、クラスへ強制されません。
つまり作成するクラスによっては不要となるメソッドは「@abstractmethod」を付与しません

また全てのクラスで共通のメソッドにも付与する必要がありません
クラスへ定義しなくてもstopメソッドが実行できています。

from abc import ABCMeta, abstractmethod
class signal(metaclass = ABCMeta):
    def stop(self):  #共通メソッド
        print('【共通】<STOP')
class aircon(signal):
    def on(self):
        print('【エアコン】<ON')
    def off(self):
        print('【エアコン】<OFF')
machine = aircon()
machine.stop()
#【共通】<STOP

解説

改めて先ほどのコードを見てみると動きが理解できるようになったでしょうか。

#抽象基底クラスをインポート
from abc import ABCMeta, abstractmethod 

#signal抽象クラスを作成
class signal(metaclass = ABCMeta):  metaクラスをABCMetaに指定

    #各メソッドにデコレータ@abstractmethodを付与
    @abstractmethod
   #共通のonメソッド
    def on(self):
        pass

    @abstractmethod
    #共通のoffメソッド
    def off(self):
        pass

#signalクラスを継承したairconクラス
class aircon(signal):   
    #airconクラスのonメソッド
    def on(self):
        #onメソッドの実行内容
        print('【エアコン】<ON')
    #airconクラスのoffメソッド
    def off(self):
        #onメソッドの実行内容
        print('【エアコン】<OFF')

class fan(signal):
    def on(self):
        print('【扇風機】<ON')
    def off(self):
        print('【扇風機】<OFF')  

#airconクラスをインスタンス化
machine = aircon()

#machineオブジェクトのon/offメソッドの実行
machine.on()
machine.off()

#【エアコン】<ON
#【エアコン】<OFF

#fanクラスをインスタンス化
machine = fan()

#machineオブジェクトのon/offメソッドの実行
machine.on()
machine.off()
#【扇風機】<ON
#【扇風機】<OFF

抽象クラスのabcをインポートします。

#抽象基底クラスをインポート
from abc import ABCMeta, abstractmethod 

抽象クラスのsignalクラスを作成 metaclass = ABCMetaメタクラスを指定

#signal抽象クラスを作成
class signal(metaclass = ABCMeta): 

継承したいクラス(airconやfan)に作成するメソッドを作成します。 @abstractmethodを付けることで、継承先クラスでのメソッドの作成を強制することができます。
処理内容が共通するメソッドや不要なメソッドは@abstractmethodを付ける必要がありません。

    #各メソッドにデコレータ@abstractmethodを付与
    @abstractmethod
   #共通のonメソッド
    def on(self):
        pass
    @abstractmethod
    #共通のoffメソッド
    def off(self):
        pass

class aircon(signal): でsignal抽象クラスを継承します。
そしてsignalクラスで作成した各メソッドの処理内容を作成します。

#signalクラスを継承したairconクラス
class aircon(signal):   
    #airconクラスのonメソッド
    def on(self):
        #onメソッドの実行内容
        print('【エアコン】<ON')
    #airconクラスのoffメソッド
    def off(self):
        #onメソッドの実行内容
        print('【エアコン】<OFF')

class fan(signal):
    def on(self):
        print('【扇風機】<ON')
    def off(self):
        print('【扇風機】<OFF')  

各クラスをインスタンス化し、machineオブジェクトを作成します。

#airconクラスをインスタンス化
machine = aircon()
#fanクラスをインスタンス化
machine = fan()

以降はメインプログラムです。
machineオブジェクトのon/offメソッドを実行します。
同じメソッド名を実行しても、machineに入れたオブジェクトによって結果が異なることが分かります。

#machineオブジェクトのon/offメソッドの実行
machine.on()
machine.off()

#【エアコン】<ON
#【エアコン】<OFF

#machineオブジェクトのon/offメソッドの実行
machine.on()
machine.off()
#【扇風機】<ON
#【扇風機】<OFF

「違うインスタンスを作成しているのだから、当たり前じゃ?」「これがメインルーチン?」と思う方は以下のプログラムを実行してみてください。

from abc import ABCMeta, abstractmethod
import abc

class signal(abc.ABC):
    @abstractmethod
    def on(self):
        pass
    @abstractmethod
    def off(self):
        pass
    def stop(self):  #共通メソッド
        print('【共通】<STOP')

class aircon(signal):
    def on(self):
        print('【エアコン】<ON')
    def off(self):
        print('【エアコン】<OFF')

class fan(signal):
    def on(self):
        print('【扇風機】<ON')
    def off(self):
        print('【扇風機】<OFF')  

class remocon():
    def on(self,machine):
        machine.on()
    def off(self,machine):
        machine.off()

remocon = remocon()
machine1 = aircon()
machine2 = fan()

remocon.on(machine1)
remocon.off(machine1)
remocon.on(machine2)
remocon.off(machine2)

#【エアコン】<ON
#【エアコン】<OFF
#【扇風機】<ON
#【扇風機】<OFF

remocon.onにairconオブジェクトを渡すと【エアコン】<ONが出力され、fanオブジェクトを渡すと 【扇風機】<ONが出力されます。
ここでエアコンや扇風機以外の機能を実装したい場合、サブルーチン側に機能を追加することで実現できます。
そしてメインルーチンのremoconは変更する必要がありません。
このように同じメソッドを実行したときに、与えたオブジェクトによって異なる振る舞いをすることがポリモーフィズムです。

まとめ

与えたオブジェクトによって異なる振る舞いをすること
複数のサブルーチンに共通のメインルーチン
共通のメインルーチンは修正する必要がない 抽象化(abc)を用いることでもポリモーフィズムを実現できる
@abstractmethodで抽象メソッドを指定する

*1:誤っていたらご指摘ください。

*2:クラスのクラスでもある

*3:メタクラスインスタンスでもある

オブジェクト指向のクラスとは

クラスを知る前にサブルーチンについて確認していきましょう。

サブルーチン(関数)とは

サブルーチン(関数)は処理をまとめたプログラムで、メインルーチンから呼び出されます。

リモコンから信号を発するイメージのプログラムを作ってみました。 この解説ではこのプログラムを軸に解説していきます。
通常であれば赤外線を送出するプログラムになりますが、簡易的にprintでリモコンから信号が出ているイラストにしました。
メインルーチンで、サブルーチンsignal_onに「00000000」の値を渡しています。
サブルーチンでは値を受け取り、リモコンのイラストを付けて出力します。

サブルーチンは何度も呼び出すことができ、呼び出す側であるメインルーチンが増えても、呼び出される側であるサブルーチンを修正する必要がありません

#サブルーチン
def signal_on(signal):
    print('【リモコン】<'+signal)

#メインルーチン
#電源を付ける信号を'00000000'とする
signal_on('00000000')

#【リモコン】<00000000

サブルーチンはC言語などでも使われていますし、比較的容易にイメージできると思います。 この時点でで分からないことがある場合は先に進まないほうが賢明です。
自分でプログラムを書いて理解を深めてみましょう。
次にいくつか単語が出てきますが、重要な点なのでしっかり理解しながら先に進みましょう。

抽象化と具体化

よく例えに出されるのが以下の例ですが、現実世界の例えはプログラムとして考えるときに混乱を招きやすいのでザックリ分かれば大丈夫です。

抽象度を上げることを抽象化、下げることを具体化と言います。
この例では左に行くほど抽象度が高いです。
「生物>哺乳類>犬>柴犬>ぽち」
「乗り物>車>消防車>車番」

具体化

具体化は分かりやすいです。
犬には沢山の犬種がありますし、哺乳類には犬以外にも猫や鯨など犬以上に種類があります。 ぽちを特定するには、「生物で、哺乳類で、犬で、柴犬の、ぽち」となります。
このように要素を絞り込んでいくことを具体化といいます。

抽象化

具体化の反対です。 「ぽちは柴犬に含まれ、犬に含まれ、哺乳類に含まれ、生物に含まれる」と、具体的な要素や概念を減らして範囲を広げていくことです。 犬と猫がいた場合そのままでは別々の生き物ですが、抽象化することで哺乳類という分類に入れることができます。
一般に子供や汎用コンピュータ*1は抽象化の能力が低いようです。
柴犬とチワワが並んでいても別の生き物だと認識し、犬という分類でとらえることができません。

クラスとは

まとめる

1つ目にサブルーチンや変数をまとめた分類のことです。

先ほどのプログラムにOFFのサブルーチンを追加します。
この規模では問題ありませんが、何十個と追加されたり、全く別の機能が追加されることがあります。
そうすると汚いプログラムになり*2、保守や仕様変更が大変になります。

#ONサブルーチン
def signal_on(signal):
        print('【リモコン】<ON:'+signal)
#OFFサブルーチン
def signal_off(signal):
        print('【リモコン】<OFF:'+signal)

#メインルーチン
signal_on('00000000')
signal_off('00000000')

#ON
#【リモコン】<ON:00000000
#OFF
#【リモコン】<OFF:00000000

そこで新たに信号系のsignalクラスを作りONとOFFをまとめることで、見やすくなったと思います。
sifnalクラスの中にon関数とoff関数があります。このようなクラス内の関数のことをメソッドと呼びます。 remo=remocon()インスタンス化、selfインスタンス化された自分自身を表しますが、詳細は後述します。

class remocon():
    #ON
    def on(self,signal):
        print('【リモコン】<ON:'+signal)
    #OFF
    def off(self,signal):
        print('【リモコン】<OFF:'+signal)

#メインルーチン
remo=remocon()
remo.on('00000000')
remo.off('11111111')

隠ぺいする

まとめることで綺麗に見える以外にもメリットがあります。
クラスをインスタンス化し、メソッドで外部とやり取りをすることで内部処理を気にすることなく処理を行うことができます。
またクラスで使われる変数には、クラス変数とインスタンス変数があります。 これらを使うことでカプセル化を行うことができます。

一気に単語が増えて頭の中がごちゃごちゃになってきたと思いますので、ひとつひとつ解説します。 とても重要なポイントなのでしっかり理解してください!

インスタンスとは

クラスを具現化したオブジェクト
難しいですね。

クラスの段階ではまだ概念だと思っていてください。
ぽちの例では犬や動物、リモコンの例ではON/OFFなどの信号をまとめたsignalがクラスになります。
「犬」や「信号」といった概念では動かすことができないので具現化します。
そのことをインスタンス化と言います。
先ほどのプログラムではこの部分がインスタンス化になります。

remocon=signal()

メリット

なぜわざわざインスタンス化する必要があるのか。
先ほどの具現化の話になりますが、クラスの段階ではまだ抽象的な概念です。
それをインスタンス化することで、実体のあるオブジェクトとして操作することできるようになります。
そして、インスタンスはいくつも作ることができます。

今回は「aircon」「fan」の2つのオブジェクトを作ります。

class remocon:
 #初期化
    def __init__(self,x):
  #インスタンス変数のmachineに代入
        self.machine = x
    #ON
    def on(self,signal):
        print('【'+self.machine+'】<ON:'+signal)
    #OFF
    def off(self,signal):
        print('【'+self.machine+'】<OFF:'+signal)

#2つインスタンス化
aircon = remocon("エアコン")
fan = remocon("扇風機")

#インスタンスごとに機器名が保持されている
aircon.on('00000000')
aircon.off('00000000')
fan.on('11111111')
fan.off('11111111')

#【エアコン】<ON:00000000
#【エアコン】<OFF:00000000
#【扇風機】<ON:11111111
#【扇風機】<OFF:11111111

解説すると、ここで「remoconクラス」の概念が「aircon」「fan」の2つのインスタンスになりました。

aircon = remocon("エアコン")
fan = remocon("扇風機")

次に渡した「エアコン」と「扇風機」の値を、「init」というメソッドで自身のインスタンス変数である「machine」に代入しました。 「init」は最初だけ実行される特別なメソッドになり、コンストラクトと呼ばれます。 ここでselfを使います。この変数はクラス内のどこからでも使うことができます。 更に詳細を知りたい方はこのブログを参考にすると良いでしょう。 python.ms

 #初期化
    def __init__(self,x):
  #インスタンス変数のmachineに代入
        self.machine = x

そのため同じon/offメソッドを使っても、インスタンスごとにカッコ内の機器名が異なるようになりました。

aircon.on('00000000')
aircon.off('00000000')
fan.on('11111111')
fan.off('11111111')

クラス変数とインスタンス変数

ではインスタンス変数とは何でしょうか。 クラスの中にはクラス変数とインスタンス変数の2種類あります。 ここを進む前に、にローカル変数とグローバル変数の知識があると良いでしょう。

クラス変数 インスタンス変数
定義する場所 classの直下 メソッドの直下
値は 全てのインスタンスで共有 インスタンスごとに独立
クラスオブジェクト
からの参照
インスタンスオブジェクト
からの参照
変更 検証を参照 検証を参照

定義する場所

classの直下にクラス変数を定義します。
クラス変数power=100を定義してみました。
インスタンス変数はself.machineという形式で定義します。

class signal:
    power =100 #クラス変数

    def __init__(self,x):
        self.machine = x #インスタンス変数

クラスオブジェクトからの参照

クラスオブジェクトからはクラス変数は参照可能です。
インスタンス変数は参照不可です。

class signal:
    power =100 #クラス変数

    def __init__(self,x):
        self.machine = x #インスタンス変数

fan = signal("扇風機")
print(signal.power)
#100 <--参照可能
print(signal.machine)
#AttributeError: type object 'signal' has no attribute 'machine' <--エラー参照不可

インスタンスオブジェクトからの参照

インスタンスオブジェクトからは、クラス変数、インスタンス変数ともに参照可能です。

class signal:
    power =100 #クラス変数

    def __init__(self,x):
        self.machine = x #インスタンス変数

fan = signal("扇風機")
print(fan.power)
#100 <--参照可能
print(fan.machine)
#扇風機 <--参照可能

値の変更

以下のプログラムの下に書いていく形で検証します。

class signal:
    power =100 #クラス変数

    def __init__(self,x):
        self.machine = x #インスタンス変数

fan = signal("扇風機")
aircon = signal("エアコン")
1.クラスオブジェクトからクラス変数を変更

変更可能かつ、全てのクラス変数が変更されました。

signal.power = 200
print(signal.power) 
print(fan.power)
print(aircon.power)

#200
#200
#200
2.インスタンスオブジェクトからクラス変数を変更

変更可能ですが、指定したインスタンスのクラス変数に限ります。*3

fan.power = 1000
print(signal.power)
print(fan.power)
print(aircon.power)
#100
#1000
#100
3.クラスオブジェクトからインスタンス変数を変更

先ほどはクラスオブジェクトからインスタンス変数は参照不可でしたが、代入することで参照できるようになりました。*4

signal.machine = "ライト"
print(signal.machine)
print(fan.machine)
print(aircon.machine)
#ライト
#扇風機
#エアコン
4.インスタンスオブジェクトからインスタンス変数を変更

変更可能ですが、指定したインスタンスインスタンス変数に限ります。

fan.machine= "扇風機改"
print(signal.machine)
print(fan.machine)
print(aircon.machine)
#AttributeError: type object 'signal' has no attribute 'machine' <--エラー
#扇風機改
#エアコン

このような特徴を用いることによりカプセル化が実現できます。

カプセル化(カプセルか、英: encapsulation)とは、データ(属性)とメソッド(手続き)を一つのオブジェクトにまとめ、その内容を隠蔽することを言う。

増やす

前項の「インスタンスとは」でインスタンス化をすることで、オブジェクトを増やすことができると学びました。(踏み込みすぎました・・・)
この仕組みはオブジェクト指向独特の機能です。

メモリ確保

初心者のときはメモリ確保については全く考えないでしょう。 しかしインスタンスとメモリ確保は密接な関係にあります。
なぜならインスタンスが生成された時点で、その分のメモリ領域が確保されます。
それにより同時に複数のインスタンスを処理することができるようになるのです。

まとめ

単語 意味
サブルーチン 関数。処理をまとめたもの
クラス サブルーチンや変数をまとめたもの
メソッド クラスにあるサブルーチン
インスタンス クラスという概念を、具体化して操作できるようにしたもの
インスタンス変数 self.(変数名)で定義
メソッドで宣言されてる
インスタンスごとに独立
クラス変数 クラスで宣言される
インスタンスに共通
カプセル化 クラスやメソッドを用いて処理を隠蔽すること

*1:それを補うために機械学習などがあります。

*2:スパゲッティコードといいます。

*3:イレギュラーな使い方でしょうか?

*4:こちらもイレギュラーな使い方でしょうか?

Linux系の解説ブログで見かける$(ドルマーク)の意味

よく見かける$(ドルマーク)

linuxの勉強を始めよう!と思って検索すると、コードの前に$(ドルマーク)が書いてあることがあります。 初心者の場合まずここで意味が分からず、躓きポイントになると思います。

意味

簡単に言うと「このコマンドを実行するよ」という意味です。 「$(ドル)」「%(パーセント)」「#(シャープ)」を見かけることもありますが、一般ユーザの場合は「$,%」、rootユーザの場合は「#」で記載されていることが多いです。

$ 一般ユーザで実行するコマンド
% 一般ユーザで実行するコマンド
# rootユーザで実行するコマンド

PowerShellコマンドプロンプトでは表示されないので混乱するかもしれませんが、実際にlinux環境を立ててみるとよく分かります。

まとめ

解説ブログやQiitaで$を見かけたら、マークに続くコマンドを入力してください。

ちなみにコメントを#で記載することもあるので、混乱を招きますね・・・

Proxy環境でPythonパッケージをオフラインインストールする方法

環境

会社でプロキシが利用されていたり、どうしてもオフラインでインストールする必要がある時を想定しています。

インストール方法

通常であればpip install パッケージ名でインストールできますが、下のエラーが出てインストールできないことがあります。 proxyで接続できないことが分かります。

WARNING: Retrying (Retry(total=4, connect-None, read-None, redirect-None, status-None)) after connection broken
by ProxyError( Cannot connect to proxy. , OSError ( Tunnei conection fai led: 407 407))': [パッケージ名]
WARNING: Retrying (Retry(total=3, connect-None, read-None, redirect-None, status-None)) after connection broken
by ProxyError( Cannot connect to proxy. , OSError ( Tunnei conection fai led: 407 407))': [パッケージ名]
WARNING: Retrying (Retry(total=2, connect-None, read-None, redirect-None, status-None)) after connection broken
by ProxyError( Cannot connect to proxy. , OSError ( Tunnei conection fai led: 407 407))': [パッケージ名]
WARNING: Retrying (Retry(total=1, connect-None, read-None, redirect-None, status-None)) after connection broken
by ProxyError( Cannot connect to proxy. , OSError ( Tunnei conection fai led: 407 407))': [パッケージ名]
by "ProxyError ( Cannot connect to proxy.',

検索するとproxyの設定を入れる方法などいくつか方法がありますが、今回はPythonのパッケージを直接ダウンロードする方法をまとめます。 pypi.org 今回はExcelを操作することができるopenpyxlをインストールします。 pypi.org

左側にあるNavigation>Download filesを選択し、最新のopenpyxl-3.0.3.tar.gz(2020.6.24現在)を任意のフォルダにダウンロードします。
パッケージによって拡張子が.whlや.gzなどありますが、そのままインストールできます。

ダウンロードが完了したらPowerShell(もしくはコマンドプロンプト)を開き、パッケージをダウンロードしたフォルダに移動します。 デスクトップに保存したときの例を示します。

PS C:\Users\ユーザ名>cd desktop
PS C:\Users\ユーザ名\Desktop>pip install --no-deps [パッケージファイル名]

パッケージファイル名は拡張子も入力してください。

インストールが完了したらpip listで、インストールされたパッケージを確認します。

>pip list

また依存関係を確認します。 パッケージを使うには、他のパッケージが要求されることがあります。 openpyxlの場合「jdcal」と「et_xmlfile」が依存関係にあるので、この2つも同じようにインストールする必要があります。 最終的に以下のように表示されれば問題ありません。

>pip check
No broken requirements found.

「pipdeptree」というパッケージを入れると、依存関係が分かりやすいので気になる方をお試しください。

以上でオフラインインストール作業は完了です。

まとめ

PyPi.orgからパッケージをダウンロード

pip install --no-deps [パッケージファイル名]でインストール

余談

ブログにまとめるときに説明文の位置に迷いますね。 画像の下に説明が多いようですが、ソースコードの場合は説明の下にソースコードが多くみられました。 基本はそのレイアウトで書いていこうと思います。

WindowsでPython開発環境を作成

はじめに

本ブログの対象者は以下のレベルです。

  • 検索やofficeなどは普通に使える
  • ダウンロードやインストールは問題なくできる
  • パソコンに関する知識がそれなりにある
  • プログラミングの基礎的な知識がある(変数や配列、繰り返し処理など)

初心者が一番最初に躓くのは開発環境だと思います。 初心者向けとありながらコマンドをどこに打ち込めばいいのかわからないサイトとか、結局答えが書いていないサイトとか。。

私もインフラ分野は初心者なので、簡単なレベルから書いていきますが、あまりにも簡単なもの(ソフトのインストールの詳細手順など)は省きます。 間違っている部分や見づらい書き方がありましたら、ご指摘いただければ幸いです。

Pythonのインストール

ダウンロード

まずは Windows パソコンで Python を使う方法から説明します 。

https://www.python.org/と入力するか、GooglePython と検索すると[Welcome to Python.org]というページが出てきます。 www.python.org

インストール

最新版は3.8.3です。(2/24現在3.8.2) 今回は Windows10の64 bit なので Windows x86-64のファイルを選びます。 3種類ありますがどれでも大丈夫です。 インストールするときにAdd Python 3.X to Pathにチェックを入れてインストールします。

インストール確認

コマンドプロンプト、もしくはWindowsPowerShellを開きます。 PowerShellLinuxのコマンドが使えるようなので、PowerShellがおすすめです。 ここでインストールしたPython のバージョンが表示されれば成功です。

> python --version
Python 3.8.3

エディタのインストール

インストール

Visual Studio CODE というコードエディターを選択します もちろんメモ帳やサクラエディタなどでもいいのですが、コードエディターを使うことで自動補完や色付けをしてくれるので効率的な作業が可能になります。 コードエディターは人によって好みが分かれるので色々試してみましょう azure.microsoft.com

日本語化

  1. viewを選択
  2. command palette を選択
  3. configure display languageを選択
  4. install additional laugageを選択
  5. Japanese Language Pack for Visual Studio Codeをインストール
  6. VScodeを再起動する。

プログラムを書く場所

左側にエクスプローラが表示されているので、ファイルを作成することができます。 pythonのプログラムであれば、「ファイル名.py」を作ることでpythonと認識してくれます。