使ってみて感じたPythonのメリットとデメリット

# 概要

ここ数ヶ月、業務でPythonを多用してきました。使用内容としては、

- 別のツール([Apache Airflow](https://www.slideshare.net/takemikami/apache-airflow-73211709)など)で使用されている言語(≒DSL)なので、仕方なく使用
- 計測データを読み込んで加工し出力する、データ加工用スクリプト言語として使用
- Webフレームワーク[Flask](https://qiita.com/ynakayama/items/2cc0b1d3cf1a2da612e4)で、Webアプリケーションを作成するための言語として使用

といったところです。その間、軽量言語であるPythonの利点を享受していましたが、同時に動的言語であるPythonの面倒さも味わいました。その詳細をざっとまとめたのが当記事になります。

# 利点

### ・Pandasがあまりにも強力

業務内では、計測データがCSVやExcelシートや[parquet](https://dev.classmethod.jp/cloud/aws/amazon-athena-using-parquet/)や[データベース](https://qiita.com/nmrmsys/items/cdeb4afa76c591acfd3f)など、様々な形式で保存されていました。結局データベースに集約させるわけですが、そこまでに

- 様々な形式のファイルを読み込み、様々な形式として保存する
- 要らないデータ(NaNなど欠けている箇所がある・データの書式がおかしいなど)を削除する
- 必要な行・列を条件を指定して抽出する
- データを[集合演算](http://sinhrks.hatenablog.com/entry/2014/11/27/232150)や[公開関数](https://www.lifewithpython.com/2013/12/python-higher-order-functions-in-standard-library.html)で一括処理する

といった操作が必要でした。それらに[Pandas](https://qiita.com/ysdyt/items/9ccca82fc5b504e7913a)がジャストミートし、Pandas経由で間接的に使用することになる[NumPy](https://qiita.com/jyori112/items/a15658d1dd17c421e1e2)と共に活躍しました。

### ・PyCharmが非常に使いやすい

社内ではMac OS上で開発していましたが、その際メインで使用していたIDEが[PyCharm](https://gammasoft.jp/python/pycharm-install-on-windows/)です。[無償版も商用利用できます](https://qiita.com/yoichiwo7/items/9c57d569d02a39fe2b9f)し、Alt+Enterからの自動修正機能(必要なモジュールのimport文追加・importの整理・自動フォーマットなど)が強力無比でした。

後述する「sys.pathを書き換えてimport」に表示部分が対応していない……といった欠点もありますが、少なくとも**単なるテキストエディタで書くより遥かに捗る**のは事実です。

### ・インタラクティブモードで文法確認が捗る

Pythonはスクリプト言語ですので、実行環境による事前の構文チェックが効きません。明らかにおかしいものはIDEがチェックしてくれ(ることもあり)ますが、

- この構文は正しかったっけ？
- この変数にこのメソッドは呼び出せたっけ？
- そもそもこの変数の型は何？

といった疑問が定期的に湧いてきます。その際、[インタラクティブモード](https://docs.pyq.jp/column/interactive.html)上でスクリプトをコピペして実行することで、任意の変数の型を調べたり、構文やメソッドの動作チェック(※例外が吐かれてもその場で実行環境が止まったりしない)をすることができます。

特に[配列などのスライス](https://qiita.com/kaeruair/items/e7f1c08915839ce3c9b4)は直感的でないことから、インタラクティブ環境でチェックしまくれるのは非常に助かりました。

### ・豊富なライブラリをすぐに使用できる

pipコマンドから様々なライブラリをインストールできるので、「あのライブラリ欲しいなー」となった際は即座に利用できるのは便利でした。Pandas以外にも[NumPy](https://qiita.com/jyori112/items/a15658d1dd17c421e1e2)や[matplotlib](https://qiita.com/skotaro/items/08dc0b8c5704c94eafb9)や[Scipy](http://programming-study.com/technology/python-scipy/)などの強力なライブラリ群が使えるのはPythonの大きな強みと言えます。

また、ローカル環境のPythonにそのまま放り込むだけでなく、PyCharm・pyenvを経由して**特定のプロジェクトにだけインストール**といったこともできるのが非常に捗りました。ローカルにインストールしているPythonと、クラウド上で動作するPythonのバージョンが違うのはよくあることでしたので……。

### ・インデントで構文を表現するとか天才かよ

括弧を多用せずとも処理構造が表現できるのは驚きでした。……逆に言えば「不用意にインデントできない」ということにもなりますが。

# 欠点

### ・メソッドチェーンしたいだけの人生だった

もちろんPythonでも[メソッドチェーンは実装できます](https://teratail.com/questions/114011)し、[Pandasの各種関数はメソッドチェーン対応](https://qiita.com/piroyoung/items/dd209801ca60a0b00c11)なのでそこはいいのです。

ですが、Pythonデフォルトの[map](https://docs.python.jp/3/library/functions.html#map)や[filter](https://docs.python.jp/3/library/functions.html#filter)がメソッドチェーン対応ではない上、[listの各種メソッド](https://docs.python.jp/3/tutorial/datastructures.html)に破壊的なものが多いため、複雑な処理を施そうとすると**1行の文字数か単文の行数が嵩む**問題が発生します。

……ここでTwitter上で「**リスト内包表記を使うべきでは**(要約)」といったツッコミが返ってきました。確かに使ったことがないので調べてみましたが、mapとfilterの仕事をこなせるので慣れれば強力な気がします。

　[pythonの内包表記を少し詳しく - Qiita](https://qiita.com/y__sama/items/a2c458de97c4aa5a98e7)

### ・型が指定できない災厄が降りかかる

Pythonは動的言語ですので、変数の型が実行時まで決定しません。いわゆる[ダックタイピング](https://ja.wikipedia.org/wiki/ダック・タイピング)なのですが、静的言語と違ってinterfaceを介しませんので、本当に**どんな型が降ってきても受け入れる**必要があります。

同じ動的言語でも、[PHP(5.4～7以降)](https://qiita.com/bokotomo/items/1ead446ef689dc45b487)や[TypeScript](https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a#関数型)の場合、変数宣言やメソッドの引数や戻り値の型を制約すれば、それが実行時に自動でチェックされたり、IDE上で型のサポート(メソッドの自動補完など)を受けられるといったことができます。

しかし、Python3.6以降に搭載された[タイプヒンティング](https://qiita.com/icoxfog417/items/c17eb042f4735b7924a3)は実行環境がどうこうするわけではなく、またライブラリがタイプヒンティング前提に組まれていないため、**メソッドの戻り値に型が指定されていない→明示的なタイプヒンティングを繰り返す必要がある**といった面倒臭さがあります。

もっとも、そこを改善しようとしますと、TypeScriptのように型宣言情報をいちいち揃える必要がありますが……。

### ・変数スコープの仕様が人類には辛すぎる

　これについては他の方の記事「[Pythonの変数スコープの話](https://qiita.com/msssgur/items/12992fc816e6adf32cff)」を参照してください。とにかく**グローバル汚染されまくる**ので、いくらIDEで「その変数名だと汚染されるから気をつけてね！(意訳)」と表示されたとしても、感謝すると言うより「なんでそんな**人類に優しくない仕様**になっているのか」感が……。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29802/a74e503b-50b6-ca73-badd-ca9201c26d86.png)
(※上記画像は、業務で使用しているコードでは勿論ありません。「[if __name__ == '__main__' の下にコードをダラダラと書く人、挙手しなさい](https://qiita.com/pashango2/items/57d8a08e53a4548fb5ad)」も参照しましょう)

### ・お前のimport仕様はおかしい

**開発中にModuleNotFoundErrorを何度見たことか。**

……[相対パスの能力に限界があるのでsys.pathの書き換えが必要](https://qiita.com/suzuki-hoge/items/f951d56290617df4279e#上にあるモジュールをインポートする)なのは本当にキツいのですがそれは。Javaのように「ディレクトリ構造と呼び出し方(≒名前空間)が一対一対応」する仕様で、C#やPHPのように名前空間を好きに設定できるわけでないのがボディーブローのように効いてきます。

### ・その他枝葉末節

- Python標準のdictが「`for key in dict`」形しかない。「`for key, val in dict`」も欲しかった
  - これについては「`for key, val in dict.items()`」でいいといった意見をいただきました
  - ただ、「キー→(無印)、値→values()、両方→items()」なので、「キー→keys()、値→values()、両方→(無印)」の方が分かりやすかったなといった印象です([Ruby](https://www.javadrive.jp/ruby/hash/index7.html)がそんな感じ)
- なんで条件演算子が「`x = (y == 1) ? 2 : 3`」じゃなくて「`x = 2 if y == 1 else 3`」とトリッキーな構文になっているの？
- なんで[docstringの書式が複数通りある](https://note.nkmk.me/python-docstring/)の？？？
- CSSセレクタの実装がクソな[BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)に[煮え湯を飲まされた]
(https://twitter.com/YSRKEN/status/1057648760883339267)。[lxml](https://lxml.de)の方が断然速いし正しく動作するやんけ！