シェル芸勉強会 meets Python

# イントロダクション
<TABLE ALIGN=CENTER><TR><TD WIDTH=400px>
 <A HREF="https://bio-shell.connpass.com/event/66089/" TARGET="_blank"><STRONG>シェル芸勉強会 meets バイオインフォマティクス vol.1 - connpass</STRONG></A>
 <A HREF="http://b.hatena.ne.jp/entry/https://bio-shell.connpass.com/event/66089/" TARGET="_blank">
 <IMG BORDER="0" SRC="http://b.hatena.ne.jp/entry/image/https://bio-shell.connpass.com/event/66089/" BORDER="0" ALT="" /></a>
 <BR>
## 背景  NGS現場の会MLで突如盛り上がったawkでデータを処理する手法についての議論を受けたツイートが起源である。...
 </TD>
 <TD WIDTH=150px>
 <a href=https://bio-shell.connpass.com/event/66089/> <IMG STYLE="float:left;margin-right:.5em;" SRC="http://capture.heartrails.com/120x120/cool/shorten?https://bio-shell.connpass.com/event/66089/" ALT="" WIDTH="120" HEIGHT="120" /></a>
 </TD></TR>
</TABLE>



先日、こんなイカ~~レた~~した勉強会がありました。
で、主催者の一人が返信をくれました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ワンライナーなら割と何でも良いと思ってます。</p>&mdash; kubor@創薬ちゃんP (@kubor_) <a href="https://twitter.com/kubor_/status/906041509086035970?ref_src=twsrc%5Etfw">2017年9月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


お題はこちらから

<TABLE ALIGN=CENTER><TR><TD WIDTH=400px>
 <A HREF="http://sssslide.com/www.slideshare.net/EmiHattori1/ss-80854726" TARGET="_blank"><STRONG>バイオシェル芸 問題のみ - SSSSLIDE</STRONG></A>
 <A HREF="http://b.hatena.ne.jp/entry/http://sssslide.com/www.slideshare.net/EmiHattori1/ss-80854726" TARGET="_blank">
 <IMG BORDER="0" SRC="http://b.hatena.ne.jp/entry/image/http://sssslide.com/www.slideshare.net/EmiHattori1/ss-80854726" BORDER="0" ALT="" /></a>
 <BR>
2017.10.18 @ 株式会社ディー・エヌ・エー（渋谷オフィス） シェル芸勉強会 meets バイオインフォマティクス vol.1 https://bio-shell.connpass.co...
 </TD>
 <TD WIDTH=150px>
 <IMG STYLE="float:left;margin-right:.5em;" SRC="http://capture.heartrails.com/120x120/cool/shorten?http://sssslide.com/www.slideshare.net/EmiHattori1/ss-80854726" ALT="" WIDTH="120" HEIGHT="120" />
 </TD></TR>
</TABLE>



## Air_LT
東京まで行けなかったのでAir_LTと称して、勝手にpythonのワンライナーについてtweetしてみました。

<TABLE ALIGN=CENTER><TR><TD WIDTH=400px>
 <A HREF="https://slideship.com/users/@y-sama/presentations/2017/10/DQCsPhWqdLqwNuvoLBSeby/" TARGET="_blank"><STRONG>bioinfoシェル芸 meets IPython - slideship.com</STRONG></A>
 <A HREF="http://b.hatena.ne.jp/entry/https://slideship.com/users/@y-sama/presentations/2017/10/DQCsPhWqdLqwNuvoLBSeby/" TARGET="_blank">
 <IMG BORDER="0" SRC="http://b.hatena.ne.jp/entry/image/https://slideship.com/users/@y-sama/presentations/2017/10/DQCsPhWqdLqwNuvoLBSeby/" BORDER="0" ALT="" /></a>
 <BR>
 https://bio-shell.connpass.com/event/66089/
Air_LT
 </TD>
 <TD WIDTH=150px>
 <a href=https://slideship.com/users/@y-sama/presentations/2017/10/DQCsPhWqdLqwNuvoLBSeby/> <IMG STYLE="float:left;margin-right:.5em;" SRC="http://capture.heartrails.com/120x120/cool/shorten?https://slideship.com/users/@y-sama/presentations/2017/10/DQCsPhWqdLqwNuvoLBSeby/" ALT="" WIDTH="120" HEIGHT="120" /></a>
 </TD></TR>
</TABLE>


僕はある程度、データ解析で使うライブラリが固定されているので、ipython startupに色々突っ込んでいます。

```00_startup.py
import sys,os
import pandas as pd
import numpy as np
import seaborn as sns
sns.set(font=["Arial Unicode MS"])
```
ただ、これがワンライナーかというと、若干疑問が生じます。
(jupyterとかatom-hydrogenとかではかなり便利ですが。)

更に...

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">セミコロンを使わないのが真のワンライナー <a href="https://twitter.com/hashtag/%E3%83%90%E3%82%A4%E3%82%AA%E3%82%B7%E3%82%A7%E3%83%AB%E8%8A%B8?src=hash&amp;ref_src=twsrc%5Etfw">#バイオシェル芸</a></p>&mdash; ことね (ktnyt) (@kotone_nyt) <a href="https://twitter.com/kotone_nyt/status/920613203679182848?ref_src=twsrc%5Etfw">2017年10月18日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


ということで、若干追加のTIPSを。

# importのワンライナー
通常使うpythonのimportは文です。
しかし、importするモジュールを動的に変化させるために組み込み関数`__import__`が用意されています。

```py
#これらは等価
import pandas
pandas = __import__('pandas')

#これらも等価
import pandas as pd
pd = __import__('pandas')

#こんなのも等価
from pandas import DataFrame as df
df = getattr(__import__("pandas"),'DataFrame')
```

[公式Document](https://docs.python.jp/3/library/functions.html?highlight=__import__#__import__)

>この関数は `import` 文により呼び出されます。 (builtins モジュールをインポートして `builtins.__import__` に代入することで) この関数を置き換えて import 文のセマンティクスを変更することができますが、同様のことをするのに通常はインポートフック (PEP 302 参照) を利用する方が簡単で、かつデフォルトのインポート実装が使用されていることを仮定するコードとの間で問題が起きないので、**このやり方は強く推奨されません。** `__import__()` を直接使用することも推奨されず、 `importlib.import_module()` の方が好まれます。

あいたー

# ワンライナー化の例

"拡張子ゲシュタルト崩壊"を例にします。

<TABLE ALIGN=CENTER><TR><TD WIDTH=400px>
 <A HREF="http://sssslide.com/www.slideshare.net/EmiHattori1/ss-80854726#14" TARGET="_blank"><STRONG>バイオシェル芸 問題のみ - SSSSLIDE</STRONG></A>
 <A HREF="http://b.hatena.ne.jp/entry/http://sssslide.com/www.slideshare.net/EmiHattori1/ss-80854726#14" TARGET="_blank">
 <IMG BORDER="0" SRC="http://b.hatena.ne.jp/entry/image/http://sssslide.com/www.slideshare.net/EmiHattori1/ss-80854726#14" BORDER="0" ALT="" /></a>
 <BR>
 バイオシェル芸 問題のみ - SSSSLIDE... 
 </TD>
 <TD WIDTH=150px>
 <IMG STYLE="float:left;margin-right:.5em;" SRC="http://capture.heartrails.com/120x90/cool?http://sssslide.com/www.slideshare.net/EmiHattori1/ss-80854726#14" ALT="" WIDTH="120" HEIGHT="120" />
 </TD></TR>
</TABLE>

> GTH.tar.gz を解凍し、GTHフォルダ内のファイル名を
次のルールで変更してください
- 拡張子が.fa、.mfa、.fas、fasta →拡張子.faに統一
- 拡張子が.fq、.fastq →拡張子.fqに統一
- ファイル名が重複した場合は上書き
https://github.com/bio-shell/study1/blob/master/data/GTH.tar.gz

pythonicに書くならこんな感じだと思います。

```py
import os
import re
import tarfile

tarfile.open('GTH.tar.gz').extractall()

fa = re.compile('.m?fa(s|sta)?$')
fq = re.compile('.f(ast)?q$')

files = list()
for file in os.listdir('GTH/'):
    files.append('./GTH/' + file)

for file in files:
    if re.search(fa, file):
        os.replace(file, re.sub(fa, '.fa', file))
    else:
        os.replace(file, re.sub(fq, '.fq', file))
```

### 1) 条件分岐は条件演算子に置きかえます。

```py
for file in files:
    if re.search(fa, file):
        os.replace(file, re.sub(fa, '.fa', file))
    else:
        os.replace(file, re.sub(fq, '.fq', file))
```

```py
os.replace(file, re.sub(fa, '.fa', file)) if re.search(fa, file) else os.replace(file, re.sub(fq, '.fq', file))
```

ifとforの順序を入れ替えて少しリファクタリングします。

```py
os.replace(file, re.sub(fa, '.fa', file) if re.search(fa, file) else re.sub(fq, '.fq', file))
```

### 2) for文は内包表記に置き換えます

```py
for file in files:
    os.replace(file, re.sub(fa, '.fa', file) if re.search(fa, file) else re.sub(fq, '.fq', file))
```

```py
[os.replace(file, re.sub(fa, '.fa', file) if re.search(fa, file) else re.sub(fq, '.fq', file)) for file in files]
```

### 3) ./GTH/を付与する処理を入れ込む
内包表記でもlambdaでもいいです。
今回はなんとなくlambdaを使います。

```py
files = list()
for file in os.listdir('GTH/'):
    files.append('./GTH/' + file)
```

- lambda

```py
files = map(lambda file: './GTH/' + file, os.listdir('GTH/'))
```

- 内包表記

```py
files = ['./GTH/' + file for file in os.listdir('GTH/')]
```

入れ込むとこんな感じです。

```py
[os.replace(file, re.sub(fa, '.fa', file) if re.search(fa, file) else re.sub(fq, '.fq', file)) for file in map(lambda file: './GTH/' + file, os.listdir('GTH/'))]
```

### 4) 正規表現を組み込む
パターンをコンパイルする必要もないのでsearch,matchの引数に渡します。

```py
[os.replace(file, re.sub('.m?fa(s|sta)?$', '.fa', file) if re.search('.m?fa(s|sta)?$', file) else re.sub('.f(ast)?q$', '.fq', file)) for file in map(lambda file: './GTH/' + file, os.listdir('GTH/'))]
```

### 5) モジュール読み込みの関数化

`__import__`に置き換えます。冗長になるけどワンライナーのためには仕方ありません。

```py
import os
import re
import tarfile

tarfile.open('GTH.tar.gz').extractall()
[os.replace(file, re.sub('.m?fa(s|sta)?$', '.fa', file) if re.search('.m?fa(s|sta)?$', file) else re.sub('.f(ast)?q$', '.fq', file)) for file in map(lambda file: './GTH/' + file, os.listdir('GTH/'))]
```

```py
__import__('tarfile').open('GTH.tar.gz').extractall()
[__import__('os').replace(file, __import__('re').sub('.m?fa(s|sta)?$', '.fa', file) if __import__('re').search('.m?fa(s|sta)?$', file) else __import__('re').sub('.f(ast)?q$', '.fq', file)) for file in map(lambda file: './GTH/' + file, __import__('os').listdir('GTH/'))]
```

### 5) タプルでくくる
2行をタプルでくくってワンライナーの完成です。

```py
(__import__('tarfile').open('GTH.tar.gz').extractall(),[__import__('os').replace(file, __import__('re').sub('.m?fa(s|sta)?$', '.fa', file) if __import__('re').search('.m?fa(s|sta)?$', file) else __import__('re').sub('.f(ast)?q$', '.fq', file)) for file in map(lambda file: './GTH/' + file, __import__('os').listdir('GTH/'))])
```

### 6) 別法
まるっとlambdaでくくっておくとか。

```py
(lambda gz,i,tar,os,re,fa,fq:(i(tar).open('{}.tar.gz'.format(gz)).extractall(),[i(os).replace(f,i(re).sub(fa,'.fa',f)if i(re).search(fa,f)else i(re).sub(fq,'.fq',f))for f in map(lambda f:'./{}/{}'.format(gz,f),i(os).listdir('{}/'.format(gz)))]))('GTH',__import__,'tarfile','os','re','.m?fa(s|sta)?$','.f(ast)?q$')
```
内包表記を排除してlambdaに統一するとか

```py
(lambda gz,i,tar,os,re,fa,fq:(i(tar).open('{}.tar.gz'.format(gz)).extractall(),map(lambda f:i(os).replace(f,i(re).sub(fa,'.fa',f)if i(re).search(fa,f)else i(re).sub(fq,'.fq',f)),map(lambda f:'./{}/{}'.format(gz,f),i(os).listdir('{}/'.format(gz))))))('GTH',__import__,'tarfile','os','re','.m?fa(s|sta)?$','.f(ast)?q$')
```

こんな感じで受け渡しも可能です。

```ps1
echo GTH| python -c"(lambda gz,i,tar,os,re,fa,fq:(i(tar).open('{}.tar.gz'.format(gz)).extractall(),[i(os).replace(f,i(re).sub(fa,'.fa',f)if i(re).search(fa,f)else i(re).sub(fq,'.fq',f))for f in map(lambda f:'./{}/{}'.format(gz,f),i(os).listdir('{}/'.format(gz)))]))(input(),__import__,'tarfile','os','re','.m?fa(s|sta)?$','.f(ast)?q$')"
```


# 最後に
pythonのワンライナーを紹介

```py
import this
```
<details><summary>The Zen of Python</summary>
<pre>The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
</pre></details>

**改行してインデントつけようよ!!**