Python3エンジニア認定基礎試験（7章～9章）

前回の記事の続きです。

# 7章 入出力

**出題数 1/ 40問(2.5%)**



### 7.1 入力と出力
* 標準入力：キーボードやファイルなどからデータを入力（`input()`関数など）
* 標準出力：コンソールへの出力など（`print()`関数など）
* 標準エラー出力：エラーメッセージの出力


### 7.2 input()関数
* キーボードからの入力値を受け取る
* 受け取ったデータは文字列に変換される
* `int()`、`float()`、`complex()`などの関数で数値のデータ型に変換可能

```Python
>>> price = int(input('値段を入力してください：'))
値段を入力してください：100
>>> print('税込み', round(price * 1.1),'円です。')
税込み 110 円です。

>>> price = int(input('値段を入力してください：'))
値段を入力してください：100.3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '100.3'
>>> price = int(input('値段を入力してください：'))
値段を入力してください：i
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'i'
```

### 7.3 print()関数、sys.stdout.write()

* `print()`関数
  * 内部で`str()`関数を使って文字列に変換して出力
  * 末尾に自動で改行が入る
    ※`print()`関数を使うと**None**も出力できる

* `sys.stdout.write()`
  * `sys.stdout`は、標準出力されたテキストファイル
  * 改行が入らずに一行で結果が出力
  * `str()`で文字列に変換しなかった場合はエラーが発生

**例**

```Python
import sys

nodata = None

print('あいうえお')
print(1 + 2)
print(nodata)

sys.stdout.write('あいうえお')
sys.stdout.write(str(1 + 2))
sys.stdout.write(str(nodata))
```

**実行結果**

```Python
あいうえお
3
None
あいうえお3None
```


### 7.4 標準出力のプロセス
* 文字列をエンコードしてからデコードする処理が含まれる
* デコードを行うには、先にエンコードされるため、文字列に変換しておく必要あり
（**エンコード：文字列→バイト列**、**デコード：バイト列→文字列**）


※符号化形式は、以下のコマンドで確認

```Python
>>> sys.stdout.encoding
'utf-8'
```




### 7.5 str()関数、repr()関数
* `str()`関数：オブジェクトを**人間が理解しやすい文字列**に変換する
* `repr()`関数：オブジェクトを**デバッグしやすい文字列**（**インタープリタに読める表現**）に変換する
※数値オブジェクトの場合は、両者とも同じ結果が出力

```Python
>>> name = 'abc'
>>> print(str(name))
abc
>>> print(repr(name))
'abc'

>>> a = 1
>>> print(str(a))
1
>>> print(repr(a))
1

>>> import datetime
>>> dt = datetime. datetime (2023, 5, 29, 10, 30, 20 , 1230)
>>> print(str(dt))
2023-05-29 10:30:20.001230
>>> print(repr(dt))
datetime.datetime(2023, 5, 29, 10, 30, 20, 1230)
```


### 7.6 stringモジュール
* 標準モジュール
  * `Template`クラスで文字列を置き換え
  * `substitute`メソッドで出力

```Python
>>> from string import Template
>>> question = '1'
>>> answer = 'B'
>>> t = Template('問題${first}の答えは${second}です。')
>>> print(t.substitute(first=question, second=answer))
問題1の答えはBです。
```



### 7.7 文字列のフォーマット

* 各フォーマット
  * Python2.6以前：**`%`（モジュロ）演算子**によるフォーマット
    * `%s`：文字列
    * `%10s`：最小フィールド幅を指定
    * `%-10s`：`-`でフィールド幅を指定して左詰に
    * `%d`：符号付き10進整数
    * `%f`：10進浮動小数点数（デフォルトの精度は6）
    * `%15.2f`：最小フィールド幅15、小数点以下の桁数2

  * Python2.6-3.6：**`format()`メソッド**によるフォーマット
    * コロン（`:`）の左側に**インデックス**、右側に**オプション**を指定
      * `:s`：文字列
      * `:`：指定なし（数値、文字列どちらでもエラー未発生）
      * `:*^15`：中寄せ、残りを*で埋める、15文字
      * `:*<15`：左寄せ、残りを*で埋める、15文字
      * `:0>10`：右寄せ、残りを0で埋める、10文字
      * `:^10`：中寄せ、残りを空白で埋める、10文字
      * `:d`：符号付き10進整数
      * `:,d`：3桁ごとにカンマで区切る、符号付き10進整数
      * `:+,d`：正の数（`+`）、3桁ごとにカンマで区切る、符号付き10進整数
      * `:f`：10進浮動小数点数（デフォルトの精度は6）
      * `:.3f`：10進浮動小数点数（精度3）
      * `:0^12.3f`：中寄せ、残りを0で埋める、最小フィールド幅12、10進浮動小数点数（精度3）
      * `:0>12.3f`：右寄せ、残りを0で埋める、最小フィールド幅12、10進浮動小数点数（精度3）
      * `:0<12.3f`：左寄せ、残りを0で埋める、最小フィールド幅12、10進浮動小数点数（精度3）
      * `:0=12.3f`：右寄せ、残りを0で埋める、最小フィールド幅12、10進浮動小数点数（精度3）

  * Python3.6以降：**f-String**によるフォーマット
    * コロン（`:`）の左側に**値**、右側に**オプション**を指定
    * `{}`内に計算式を書ける


```Python
>>> item = '本'
>>> price = 1000
>>> '%sは%d円です。' % (item, price)
'本は1000円です。'

>>> print('%7.3f' % price)
1000.000
>>> print('%8.3f' % price)
1000.000
>>> print('%9.3f' % price)
 1000.000
>>> print('%9.2f' % price)
  1000.00
>>> print('%s' % ('abc'))
abc
>>> print('%10s' % ('abc'))
       abc
>>> print('%-10s' % ('abc'))
abc
>>> print('%d' % (123.456789123))
123
>>> print('%f' % (123.456789123))
123.456789
>>> print('%15.2f' % (123.456789123))
         123.46

>>> '{}は{}円です。'.format(item, price)
'本は1000円です。'
>>> '{item2}は{price2}円です。'.format(item2='筆箱', price2='200')
'筆箱は200円です。'

>>> x = 'abc'
>>> y = 'def'
>>> print('{0} {1}'.format(x, y))
abc def
>>> print('{1} {0}'.format(x, y))
def abc

>>> p = [300, 100, 200]
>>> print('A：{0[2]} B：{0[0]} C：{0[1]}'.format(p))
A：200 B：300 C：100

>>> print('{:s}'.format('abc'))
abc
>>> print('{:s}'.format(123))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Unknown format code 's' for object of type 'int'
>>> print('{:}'.format('abc'))
abc
>>> print('{:}'.format(123))
123

>>> print('{:*^15}'.format('abc'))
******abc******
>>> print('{:*<15}'.format('abc'))
abc************
>>> print('{:0>10}'.format('abc'))
0000000abc
>>> print('{:^10}'.format('abc'))
   abc    

>>> print('{:d}'.format(123.45))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Unknown format code 'd' for object of type 'float'
>>> print('{:d}'.format(123))
123
>>> print('{:d}'.format(123,45))
123

>>> print('{:,d}'.format(100000))
100,000
>>> print('{:,d}'.format(1000000))
1,000,000
>>> print('{:,d}'.format(10000000))
10,000,000
>>> print('{:,d}'.format(100000000))
100,000,000

>>> print('{:+,d}'.format(100000))
+100,000
>>> print('{:+,d}'.format(1000000))
+1,000,000
>>> print('{:+,d}'.format(10000000))
+10,000,000
>>> print('{:+,d}'.format(100000000))
+100,000,000

>>> print('{:f}'.format(100))
100.000000
>>> print('{:.3f}'.format(100))
100.000

>>> print('{:0^12.3f}'.format(100))
00100.000000
>>> print('{:0>12.3f}'.format(100))
00000100.000
>>> print('{:0<12.3f}'.format(100))
100.00000000
>>> print('{:0=12.3f}'.format(100))
00000100.000

>>> f'{item}は{price}円です。'
'本は1000円です。'
>>> F'{item}は{price}円です。'
'本は1000円です。'

>>> discount = 0.2
>>> f'{item}は{price * (1 - discount)}円です。'
'本は800.0円です。'
>>> f'{item}は{price * (1 - discount):d}円です。'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Unknown format code 'd' for object of type 'float'
>>> f'{item}は{price * (1 - discount):f}円です。'
'本は800.000000円です。'
>>> f'{item}は{round(price * (1 - discount))}円です。'
'本は800円です。'
```


* 手作業でのフォーマット
  * `rjust()`メソッド
  * `ljust()`メソッド
  * `center()`メソッド
  * `zfill()`メソッド

```Python
>>> name = 'abcdefg'
>>> name.rjust(10, '_')
'___abcdefg'
>>> name.ljust(10, '_')
'abcdefg___'
>>> name.center(10, '_')
'_abcdefg__'

>>> '20'.zfill(7)
'0000020'
>>> '-20'.zfill(7)
'-000020'
```






### 7.8 ファイルオブジェクト
* ファイルを読み書きするためのデータ
  * `open()`や`write()`を使用


* ファイルを開く（`open()`）
  * `変数 = open('ファイル名', 'モード', 'エンコーディング')`
  * エンコーディング：指定なしの場合はプラットフォーム依存
  * モード：以下の①～③を組み合わせた形で使用（指定なしの場合は`r`）

    ①
    * `r`：読み込み用(ファイルがない場合はエラー)
    * `w`：書き込み用(上書き)
    * `a`：書き込み用(追記)
    * `x`：書き込み用(新規ファイル生成、ファイルが既にある場合はエラー)

    ②
    * `t`：テキストモード（内容をテキストとみなして処理）
    * `b`：バイナリモード（バイト列のまま処理、エンコーディングは指定できない）

    ③
    * `+`：更新用（ 読み書き両方を指定）

```Python
>>> f = open('abc.txt', 'wb+')
>>> f.close()
>>> f = open('abc.txt', 'r', encoding='shift_jis')
>>> f.close()
>>> f = open('abc.txt', 'rb', encoding='shift_jis')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: binary mode doesn't take an encoding argument
```

* ファイルを開く（`with open()`）
  * 処理中に例外が発生しても必ず閉じる
  * `with`キーワードを使わない場合は`close()`


### 7.9 ファイルオブジェクトのメソッド

* ファイルの内容を読み込む
  * `read(文字数)`
    * 指定した文字数のみ
    * 文字数がない場合や負の数のときはすべて返す
    * 終端に達した後は空の文字列`''`を返す

  * `readline()`
    * 1行ずつ

  * `readlines()`
    * 行ごとのリスト

  * `for line in 変数:`
    * 1行ずつ


```Python
>>> with open("sample1.txt", encoding="UTF-8") as f:
...     text3 = f.read(3)
...
>>> text3
'あいう'

>>> with open("sample1.txt", encoding="UTF-8") as f:
...     text = f.read()
...
>>> text
'あいうえお\nかきくけこ\nさしすせそ'
>>> print(text)
あいうえお
かきくけこ
さしすせそ

>>> f = open("sample1.txt", encoding="UTF-8")
>>> f.readline()
'あいうえお\n'
>>> f.readline()
'かきくけこ\n'
>>> f.readline()
'さしすせそ'
>>> f.readline()
''
>>> f.close()

>>> with open("sample1.txt", encoding="UTF-8") as f:
...     text_list = f.readlines()
...
>>> text_list
['あいうえお\n', 'かきくけこ\n', 'さしすせそ']

>>> with open("sample1.txt", encoding="UTF-8") as f:
...     for line in f:
...         print(line, end="")
...
あいうえお
かきくけこ
さしすせそ>>>
```



* ファイルに内容を書き込む：`write(文字列)`
  * `write()`メソッド書き込んだ時点では、メモリに一時保管されているだけ
  * ファイルを閉じた時点で書き込みが行われる
  * 書き込まれた文字数を返す
  * 文字列以外（数値データなど）を書き込むと**TypeError**になる

```Python
>>> fw = open('sample2.txt', 'w')
>>> fw.write(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: write() argument must be str, not int
>>> fw.write('abcdefg')
7
>>> fw.close()
```


* 先頭文字から数えた現在位置を扱う
  * `tell()`
    * バイナリモードではファイルの先頭から数えたバイト数を返す
    * テキストモードでは不明瞭な値を返す（全角は2バイト、半角は1バイト）

  * `seek(オフセット値, 基準点)`
    * ファイルの特定の位置に移動し、先頭からのバイト数を返す
    * `seek`の第2引数
  0：ファイルの先頭
  1：現在位置
  2：ファイルの末尾
  ※テキストモードの場合、基準点は**0**のみ有効（例外として、唯一の有効なオフセット値は`f.tell()`から返された値か**0**のいずれか）

```Python
>>> f = open('sample2.txt', 'rb+')
>>> f.read(2)
b'ab'
>>> f.read(3)
b'cde'
>>> f.tell()
5
>>> f.read(1)
b'f'
>>> f.tell()
6
>>> f.read()
b'g'
>>> f.read()
b''
>>> f.seek(2, 0)
2
>>> f.read(1)
b'c'
>>> f.seek(2, 1)
5
>>> f.read()
b'fg'
>>> f.seek(-3, 2)
4
>>> f.read(1)
b'e'
>>> f.close()

>>> f = open('sample2.txt', 'r')
>>> f.seek(2, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
io.UnsupportedOperation: can't do nonzero cur-relative seeks
>>> f.seek(0, 1)
0
>>> f.seek(0, 2)
7
>>> f.seek(-3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: negative seek position -3
>>> f.close()
```



### 7.10 jsonファイルの操作

* シリアライズ（直列化）
  * 複数の要素を一列に並べる操作や処理
  * `dump()`関数または`dumps()`関数によりデータ構造オブジェクトをJSON文字列に変換
    * `json.dump(データ構造オブジェクト, ファイルオブジェクト)`
    * `json.dumps(データ構造オブジェクト)`
    ※サポートしていない型は拡張する必要あり

* デシアライズ
  * シリアライズされたデータを元のオブジェクトに復元する処理
  * `load()`関数または`loads()`関数によりJSON文字列をデータ構造オブジェクトに変換
    * `json.load(ファイルオブジェクト)`
    * `json.loads(文字列)`


```Python
>>> import json
>>> data = [3, "f"]
>>> json.dumps(data)
'[3, "f"]'
>>> type(data)
<class 'list'>
>>> type(json.dumps(data))
<class 'str'>

>>> f = open("sample4.json", 'w')
>>> data = [3, "f"]
>>> json.dump(data, f)
>>> f.close()

>>> with open('sample4.json', 'r') as f:
...     data2 = json.load(f)
...
>>> data2
[3, 'f']
>>> type(data2)
<class 'list'>
```


# 8章 エラーと例外

**出題数 4/ 40問(10%)**


### 8.1 構文エラーと例外
* エラーの種類
  * 構文エラー
    * 構文の誤りにより発生したエラー
      * **SyntaxError**
      * **IndentationError**
  * 例外
    * 構文エラー以外のエラー（構文は正しいがプログラムの実行中に検知）
      * **ZeroDivisionError**
      * **NameError**
      * **TypeError**
      * **ValueError**
      * **UnicodeError**
      * **UnicodeDecodeError**
      * **IndexError**




### 8.2 例外処理
* `try`文を使用

```Python
>>> a + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> try:
...     a + 2
... except NameError:
...     print("NameErrorです")
... except:
...     print("何かのエラーが起きています")
...
NameErrorです
```



### 8.3 例外の強制発生
* `raise`文を使用

```Python
>>> raise NameError("変数名が定義されていません")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: 変数名が定義されていません

>>> try:
...     raise NameError("変数名が定義されていません")
... except NameError as e:
...     print(e)
...
変数名が定義されていません
```



* 例外発生時の引数を変数として受け取る

```Python
>>> try:
...     raise Exception('例外発生1', '例外発生2')
... except Exception as e:
...     x, y = e.args
...     print(x)
...     print(y)
...
例外発生1
例外発生2
```



### 8.4 クリーンアップ動作
* エラーでもエラーでなくても最後に必ず実行される処理
* `try`～`finally`文を使用
* もしくは`with`文により、オブジェクト（ファイルなど）を使用後すぐに適切な方法でのクリーンアップ動作を保証した形で利用できる

```Python
>>> try:
...     raise NameError
... finally:
...     print("終了")
...
終了
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
NameError

>>> try:
...     print("try内の実行")
... finally:
...     print("終了")
...
try内の実行
終了
```


### 8.5 例外処理における役割分担
* `try`
  * 例外が発生しそうな処理
  * `try`節の実行中にエラーが発生した場合、`try`節中の残りのコードは実行されず、`except`節が処理される

* `except`
  * 例外発生時に実行する処理
  * 後ろの例外を省略すると**ワイルドカード**になる
  * `except`節で定義していない例外が発生した場合、`finally`節の処理が実行された後に例外が出力（`finally`節の先行処理）

* `else`
  * 例外が発生しなかった場合の処理
* `finally`
  * 常に実行


```Python
>>> def divide(x, y):
...     try:
...         result = x / y
...         print("tryの実行")
...     except ZeroDivisionError:
...         print("0で割ることはできません")
...     else:
...         print("計算結果", result)
...     finally:
...         print("計算終了")
...
>>> divide(3, 0)
0で割ることはできません
計算終了
>>> divide(3, 2)
tryの実行
計算結果 1.5
計算終了
>>> divide(3, '2')
計算終了
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'int' and 'str'
```


# 9章 クラス

**出題数 2/ 40問(5%)**


### 9.1 クラス、インスタンス、オブジェクト、メソッド

* クラス
  * オブジェクトの設計図のこと（実体を表現するための雛形）
  * `def __init__(self)`:関数によりインスタンスを生成する際の処理を定義

* インスタンス
  * クラスを使って生成したオブジェクト

* オブジェクト
  * クラスやインスタンスの総称
  * 型がある
  * オブジェクトの属性は`オブジェクト名.属性名`で参照（**属性参照**）

* メソッド
  * クラスに定義された関数（`def メソッド名(self):`）
  * インスタンスからはメソッドとして呼び出される
    * `インスタンスオブジェクト.メソッド名(関数の引数)`
  * クラスからは関数として呼び出される
    * `クラスオブジェクト.関数名(インスタンスオブジェクト, 関数の引数)`


```Python
>>> class Person:
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
...     def say_hello(self, name):
...         print("Hello, {}. I am {}.".format(name, self.name))
...
>>> male1 = Person("Tarou", 20)
>>> male2 = Person("Satoshi", 25)
>>> print(male1.name)
Tarou
>>> print(male2.name, male2.age)
Satoshi 25
>>> male1.say_hello("Hanako")
Hello, Hanako. I am Tarou.
```

```Python
>>> class Sample:
...     def __init__(self, name):
...         self.name = name
...         print(name)
...
>>> x = "abc"
>>> s = Sample()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Sample.__init__() missing 1 required positional argument: 'name'
>>> s = Sample(x)
abc
>>> s.__init__(x)
abc
>>> Sample.__init__(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Sample.__init__() missing 1 required positional argument: 'name'
>>> Sample.__init__(s, x)
abc

>>> class Sample2:
...     def aaa(self, name):
...         self.name = name
...         print(name)
...
>>> s = Sample2()
>>> x = "abc"
>>> s.aaa(x)
abc
>>> Sample2.aaa(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Sample2.aaa() missing 1 required positional argument: 'name'
>>> Sample2.aaa(s, x)
abc
```



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

* インスタンス変数
  * インスタンスごとに**独自の値**を持たせることができる
  * 定義・参照
    * 定義：`self.変数名`
    * クラス直下から参照：`self.変数名`
    * 関数から参照：`self.変数名`
    * クラス外から参照：`インスタンス名.変数名`

* クラス変数
  * クラスの中で変数を定義すると、**どのインスタンスにも共通する値**を持たせることができる
  * 定義・参照
    * クラスの中で定義：`変数名`
    * クラス直下から参照：`変数名`
    * 関数から参照：`self.変数名`
    * クラス外から参照：`クラスオブジェクト.変数名`または`インスタンス名.変数名`


```Python
>>> class Sample:
...     list_a = []
...     def add_list_a(self, data):
...         self.list_a.append(data)
...
>>> sample1 = Sample()
>>> sample1.add_list_a("データ1")
>>> sample2 = Sample()
>>> sample2.add_list_a("データ2")
>>> Sample.list_a
['データ1', 'データ2']
>>> sample1.list_a
['データ1', 'データ2']
>>> sample2.list_a
['データ1', 'データ2']
```



### 9.3 継承
* クラスの持つデータ属性やメソッドを引き継ぐ
* 親クラスと同じメソッド名を子クラスで定義すると、親クラスのメソッドを上書きできる
* `super()`は親クラスを指す
* 多重継承：複数のクラスを継承（**例：クラスAから作成されたB、Cを継承するDを作成**）

```Python
>>> class Person:
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
...
>>> class Employee(Person):
...     def __init__(self, id):
...         self.id = id
...
>>> tarou.name = "Tarou"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'tarou' is not defined
>>> tarou = Employee("0012")
>>> tarou.name = "Tarou"
>>> tarou.age = 20
>>> print(tarou.name, tarou.age, tarou.id)
Tarou 20 0012
>>> tarou = Employee("0012")
>>> print(tarou.name, tarou.age, tarou.id)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Employee' object has no attribute 'name'
```

```Python
>>> class Person:
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
...
>>> class Employee(Person):
...     def __init__(self, name, age, id):
...         super().__init__(name, age)
...         self.id = id
...
>>> tarou = Employee("Tarou", 20, "0012")
>>> print(tarou.name, tarou.age, tarou.id)
Tarou 20 0012
```


### 9.4 プライベートメソッド・プライベート変数
* クラス内からのみ呼び出せる（クラス外からは参照できない）
* メソッド名・変数名の先頭にアンダースコア（_）を2つ付ける
* どうしても呼び出したい場合は、`インスタンス名._クラス名__関数名()`、`インスタンス名._クラス名__変数名`で呼び出す

```Python
>>> class Employee:
...     def __init__(self, name):
...         self.__name = name
...
>>> e = Employee('Yamada')
>>> e.name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Employee' object has no attribute 'name'
>>> e._Employee__name
'Yamada'
```




### 9.5 イテレータ・ジェネレータ
* イテレータ
  * クラスを使用してイテレータを実装できる
  * `__iter__`メソッド、`__next__`メソッドを使用


* ジェネレータ
  * 繰り返し処理を書くときに使用
  * `yield`式を使用
  * ジェネレータが返すオブジェクトの型は**generatorクラス型**
  * ジェネレータ関数作成時には要素数は確定しておらず、他から要素を与えられて初めて確定する
  * リスト内包表記での記述も可能

```Python
>>> def word(data):
...     for s in data:
...         yield s
...
>>> for one_word in word("sports"):
...     print(one_word)
...
s
p
o
r
t
s
>>> type(word)
<class 'function'>
>>> f = word("sports")
>>> type(f)
<class 'generator'>
```




　
　
　

エンジニアファーストの会社　[株式会社CRE-COエンジニアリングサービス](https://www.cre-co.jp/)