nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

依存性逆転の法則の学習

依存性逆転の原則 (Dependency Inversion Principle)

依存関係逆転の原則は柔軟なシステムの作り方を教えてくれます。 最も柔軟なシステムは、ソースコードの依存関係がインターフェイスだけを参照している場合です。

上位クラスの具象クラスと下位クラスの具象クラスがあります。

上位クラスの具象クラスから下位クラスの具象クラスのインスタンスを直接生成すると、下位クラスの変更の影響を上位クラスが強く受けてしまいます。

そこで、以下の手順で実施できるようにします。

(1) 間に抽象クラスを挟む

(2) DIを用いる

参考リンク

Pythonでモジュールをインポートするときの構文

はじめに

関数の定義と関数を利用する処理を同じファイルに記述すると、コード行数が膨大になります。

また、関数を再利用しにくいです。

そこで、関数の定義を別ファイルに分けて、関数の定義(モジュール)を読み込む(インポート)方法をとります。

使用するモジュール定義

今回は以下のモジュールを使用します

[dos.py]

class Dog:
    # property
    voice = "bow!"
    
    # method
    def bark(self):
        print(self.voice)

モジュールのインポート方法1

クラス名が必要です。

import health

import dogs

dog = dogs.Dog()

dog.bark()

モジュールのインポート方法2

普段はこちらを使用したほうがいいと思います。 クラス名が必要ありません。

from dogs import Dog

dog = Dog()

dog.bark()
class Dog:
    # property
    voice = "bow!"
    
    # method
    def bark(self):
        print(self.voice)

参考リンク

jupyterノートブックで、pandas_datareaderが見つからない問題の対処

エラーメッセージ

---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-1-86720d1c88cc> in <module>()
      7 import matplotlib.pyplot as plt
      8 import numpy as np
----> 9 import pandas_datareader
     10 import sklearn
     11 import sklearn.linear_model

ModuleNotFoundError: No module named 'pandas_datareader'

対処方法

note.mu

構造化束縛 [C++17]

構造化束縛

C++17で追加された構造化束縛は多値を分解して受け取るための変数宣言の文法です。

多値を受け取るためには、これまでは多値をかたまりで受け取るか、ライブラリで分解して受け取るしかありませんでした。

構造化束縛を使うと、少ないコード量で多値を分解して受け取ることが可能です。

多値を受け取るコードの比較

#include <iostream>
#include <tuple>

std::tuple < int, double, std::string > get_tuple_value()
{
    return { 1, 2.0, "hello" };
}


int main(void){
    
    // 多値を受け取る方法(多値をかたまりで受け取る)
    auto result = get_tuple_value();
    std::cout << "b : " << std::get<0>(result) << std::endl;
    std::cout << "c : " << std::get<1>(result) << std::endl;
    std::cout << "d : " << std::get<2>(result) << std::endl;
    
    // 多値を受け取る方法(ライブラリで分解して受け取る)
    int param1;
    double param2;
    std::string param3;
    
    std::tie(param1, param2, param3) = get_tuple_value();
    std::cout << "b : " << param1 << std::endl;
    std::cout << "c : " << param2 << std::endl;
    std::cout << "d : " << param3 << std::endl;
    
    // 多値を受け取る方法(C++17)
    auto [b, c, d] = get_tuple_value();;
    
    std::cout << "b : " << b << std::endl;
    std::cout << "c : " << c << std::endl;
    std::cout << "d : " << d << std::endl;
}
b : 1
c : 2
d : hello
b : 1
c : 2
d : hello
b : 1
c : 2
d : hello

if文内、switch文内、range-based for文内で使用してみる

if, switch, range-based for文で使用する。

#include <iostream>
#include <tuple>
#include <map>
#include <vector>

int main(void){
    std::tuple<int, double, std::string> expr{5, 2.0, "test"s };    // "test"sとすることでstd::string型の文字列リテラルとなる
    
    // 構造化束縛はif文で使用可能です
    if ( auto[a, b, c] = expr ; a == 5 )    // 初期化文付き条件文 (C++17)
    {
        std::cout << "a : " << a << ", b : " << b << ", c : " << c << std::endl;
    }
    
    
    // 構造化束縛はswitch文で使用可能です
    switch ( auto[a, b, c]  = expr; a )    // 初期化文付き条件文 (C++17)
    {
        case 5:
            std::cout << "a : " << a << std::endl;
            std::cout << "b : " << b << std::endl;
            std::cout << "c : " << c << std::endl;
            break;
            
        default:
            break;
    }
    
    std::vector<std::tuple<int, double, std::string>> map_Prodct;
    map_Prodct.push_back(expr);
    map_Prodct.push_back(expr);
    map_Prodct.push_back(expr);
    map_Prodct.push_back(expr);
    map_Prodct.push_back(expr);            
    
    // 構造化束縛は[range-based for文]でも使用可能です
    for ( auto[a,b,c] : map_Prodct )
    {
        std::cout << "a : " << a << ", b : " << b << ", c : " << c << std::endl;
    }
}
a : 5, b : 2, c : test
a : 5
b : 2
c : test
a : 5, b : 2, c : test
a : 5, b : 2, c : test
a : 5, b : 2, c : test
a : 5, b : 2, c : test
a : 5, b : 2, c : test

使用例

#include <iostream>
using namespace std;
int main(void){
  {
    int ar[] = {3, 1, 4};

    // 配列を分解する。
    // ar[0]がaに代入され、
    // ar[1]がbに代入され、
    // ar[2]がcに代入される。
    // 分解する要素数は、配列の要素数と同じであること
    auto [a, b, c] = ar;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
  }
  std::cout << std::endl;

  // 参照の例
  {
    int ar[] = {3, 1, 4};
    int (&rar)[3] = ar;
    auto [a, b, c] = rar;

    // ar[1]を値2に書き換える
    b = 2;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
  }
}

Pythonでプライベートメンバ変数をクラスに定義する [Python]

Pythonのプロパティを使う方法

Pythonでは、クラスのカプセル化を実現する際は、プロパティを用いるほうがいいと思います。

getter, setterを作ったとしても、使用者側がそれを使ってくれる保証がありません。(´;ω;`)

あまり良くない書き方 その3 getter/setter - Python学習講座

コード

class Car(object):
    def __init__(self, model=None):
        self.model = model

    def run(self):
        print('run')


class ToyotaCar(Car):
    def run(self):
        print('fast')


class TeslaCar(Car):
    def __init__(self, model="Model S", enable_run=False):
        # 親のinit関数を呼び出す
        super().__init__(model)
        # プライベートメンバ変数
        self.__enable_auto_run = enable_run

    @property
    def enable_auto_run(self):
        return self.__enable_auto_run

    @enable_auto_run.setter
    def enable_auto_run(self, is_enable):
        self.__enable_auto_run = is_enable

    def run(self):
        print('super fast')

    def auto_run(self):
        print('auto_run')

car = Car()
car.run()

print('########')

toyota_car = ToyotaCar('Lexus')
print(toyota_car.model)
toyota_car.run()

print('########')

# コンストラクタで、プライベートメンバ変数(__enable_auto_run)に対して、Falseの値をセットする
tesula_car = TeslaCar('Model_S', False)
print(tesula_car.enable_auto_run)

# Setterを通して、プライベートメンバ変数(__enable_auto_run)に対して、Trueの値をセットする
tesula_car.enable_auto_run = True
print(tesula_car.enable_auto_run)

出力イメージ

run
########
Lexus
fast
########
False
True

クラスのメソッドのオーバーライドとsuperによる親メソッドの呼び出し [Python]

クラスのメソッドのオーバーライドとsuperによる親メソッドの呼び出し

<コード>

class Car(object):
    def __init__(self, model=None):
        self.model = model

    def run(self):
        print('run')


class ToyotaCar(Car):
    def run(self):
        print('fast')


class TeslaCar(Car):
    def __init__(self, model="Model S", enable_run=False):
        # 親のinit関数を呼び出す
        super().__init__(model)
        self.enable_auto_run = enable_run

    def run(self):
        print('super fast')

    def auto_run(self):
        print('auto_run')


car = Car()
car.run()

print('########')

toyota_car = ToyotaCar('Lexus')
print(toyota_car.model)
toyota_car.run()

print('########')

tesula_car = TeslaCar('Model_S', True)
print(tesula_car.model)
print(tesula_car.enable_auto_run)
tesula_car.run()
tesula_car.auto_run()

<出力結果>

run
########
Lexus
fast
########
Model_S
True
super fast
auto_run