【備忘録】Python

Java, JavaScript(ES5)経験者が、Pythonでハマったこと、分からなかったことを書いていきます。



# Python

### 暗黙の型変換

以下のように`文字列+数値`を行うとエラーになります。

```python
x = 1
print("x=" + x)
#TypeError: must be str, not int
```

### インデックス`[::2]`は、2ステップごと

```shell-session:ipython
In [15]: b = [1,2,3,4,6,7]
In [16]: b[::2]
Out[16]: [1, 3, 6]
```

### `//`は整数の除算（切り捨て）

```shell-session:ipython
In [18]: 10//3
Out[18]: 3

In [19]: 10 /3 
Out[19]: 3.3333333333333335
```

### 文字列リテラルを並べると、結合される

```plain:Ipython
    In [1]: "a" "b"
    Out[1]: 'ab'
    In [2]: "a""b"
    Out[2]: 'ab'
```

便利な機能なんですがこのおかげで、「末尾カンマを忘れてもエラーが出ない」という現象が発生します。

```plain
In [478]: a = [
     ...: "a",
     ...: "b"
     ...: "c"]
In [479]: a
Out[479]: ['a', 'bc']
```

### `itertools.groupby`
pandasを使わなくてもgroupbyすることができます。
ただソート済である必要があります。

```plain:IPython_Console
In [43]: data = ["a","b","b","b", "a"]
    ...: data = sorted(data)
    ...: for key, group in itertools.groupby(data):
    ...:     print(key, len(list(group)))
    ...:
a 2
b 3
```

https://docs.python.jp/3/library/itertools.html#itertools.groupby

### 正規表現にマッチした文字列を取得
`m.group(0)`はマッチした文字列全体を表す。

```python
m = re.search(r"([a-z]+)\s*=\s*([0-9]+)", "index = 123")

if m:
    print(m.group(0))                # ->  "index = 123"
    print(m.group(1))                # ->  "index"
    print(m.group(2))                # ->  "123"
```

### listの`index`メソッドで、要素が見つからないと`ValueError`を返す。
Java, JavaScriptだと要素が見つからない場合、`-1`を返します。

### 末尾にカンマがあってもよい
リストや辞書を宣言する際、末尾にカンマがあってもエラーになりません。

```python
l = [1,2,]
d = {"a":1,}
```

### base64でエンコードして文字列に変換


```
In [1]: encoded = base64.b64encode(b'data to be encoded')
In [2]: type(encoded)
Out[2]: bytes
In [3]: encoded.decode("ascii")
Out[3]: 'ZGF0YSB0byBiZSBlbmNvZGVk'
```

https://docs.python.jp/3/library/base64.html 参考

### type関数の戻り値の型

```python
type({"a":1}) == dict # True
type({"a":1}) == "dict" # False
```

>オブジェクトの型の判定には、 isinstance() 組み込み関数を使うことが推奨されます。これはサブクラスを考慮するからです。

https://docs.python.jp/3/library/functions.html#type 引用

### 2次元配列を`[[0]*2]*2`のように宣言するのは良くない


```python
a = [[0]*2]*2
print(a)
# [[0, 0], [0, 0]]
a[0][1] = 1
print(a)
# [[0, 1], [0, 1]]
# a[1][1]も更新されている？
```
http://delta114514.hatenablog.jp/entry/2018/01/02/233002 参照

### `fileobject#readline`は改行文字が終端に残る

```python
with open('sample.txt') as f
    l = f.readline()
```

>f.readline() はファイルから 1 行だけを読み取ります。改行文字 (\n) は読み出された文字列の終端に残ります。

https://docs.python.org/ja/3/tutorial/inputoutput.html#methods-of-file-objects

# IPython

* `?`でのドキュメント閲覧、`??`でソースの閲覧
* `%xmode Verbose`で、詳細なトレースバックを表示
* `%timeit` : 複数回実行して測定してくれる。

### モジュールを自動リロード
「pyファイルをエディタで修正⇒ipythonで確認」を繰り返すとき、欲しい機能です。

```shell-session
In [1]: %load_ext autoreload
In [2]: %autoreload 2
```

https://ipython.org/ipython-doc/3/config/extensions/autoreload.html
http://sandmark.hateblo.jp/entry/2017/10/22/180000
https://qiita.com/Accent/items/f6bb4d4b7adf268662f4

# matplotlib

### (WIP) 日本語を使う場合
https://qiita.com/yniji/items/3fac25c2ffa316990d0c


### ipython起動時の処理（よく使うimport文など）を設定
 ipythonプロファイルを生成する。

```shell-session
$ ipython3 profile create
```

```py:ipython_config.py
c.InteractiveShellApp.exec_lines = [
    'import numpy as np',
    'import matplotlib.pyplot as plt',
    'import pandas as pd',
    '%load_ext autoreload',
    '%autoreload 2'
]
```

[Jupyter Notebook起動時に、インポート・matplotlibの設定を自動実行する - Qiita](https://qiita.com/yoshrc/items/fc7749726f484504c2b7)


### `%matplotlib inline`でエラー
画像を表示できないコンソール（Windows Cmder）で実行すると、以下のエラーが発生しました。
原因は、画像が表示できない環境で実行したからです。

```
In [1]: %matplotlib inline

UnknownBackend: No event loop integration for 'inline'. Supported event loops are: qt, qt4, qt5, gtk, gtk2, gtk3, tk, wx, pyglet, glut, osx
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/37903/ff68618d-8581-03ac-2249-bf9764ed4f6b.png)

https://stackoverflow.com/questions/42616768/matplotlib-inline-doesnt-work-on-ipython-and-jupyter-console 参考

# numpy

### 配列要素に`None`が含まれていると、`sum()`でエラー

```
In [5]: vals1 = np.array([1, None, 3,4])
In [6]: vals1.sum()
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
```

# Pandas

### `pivot_table`メソッドの`values`オプションに`list`を渡すと、列方向のMultiIndexが生成される

`values`に文字列（列名）を渡した場合

```IPython_Console
In [33]: import seaborn as sns
    ...: titanic = sns.load_dataset("titanic")
    ...: p = titanic.pivot_table("survived", index="sex", columns="class")
    ...: p
Out[33]:
class      First    Second     Third
sex
female  0.968085  0.921053  0.500000
male    0.368852  0.157407  0.135447

In [36]: p.columns
Out[36]: CategoricalIndex(['First', 'Second', 'Third'], categories=['First', 'Second', 'Third'], ordered=False, name='class', dtype='category')

In [37]: p["First"]
Out[37]:
sex
female    0.968085
male      0.368852
Name: First, dtype: float64
```

`values`に`list`（列名のlist）を渡した場合

```IPython_Console
In [38]:  p2 = titanic.pivot_table(values=["survived"], index="sex", columns="class")

In [39]: p2
Out[39]:
        survived
class      First    Second     Third
sex
female  0.968085  0.921053  0.500000
male    0.368852  0.157407  0.135447

In [40]: p2.columns
Out[40]:
MultiIndex(levels=[['survived'], ['First', 'Second', 'Third']],
           labels=[[0, 0, 0], [0, 1, 2]],
           names=[None, 'class'])

In [41]: p2["survived"]["First"]
Out[41]:
sex
female    0.968085
male      0.368852
Name: First, dtype: float64
```

### 1個のファイルに複数のDataFrameを出力する

```python
with open("sample.csv", mode="w") as f:
    f.write("title1\n")
    df1.to_csv(f)
    f.write("title2\n")
    df2.to_csv(f)   
```

※pandas 0.23.1 では、正しく動かない（リグレッションバグ）。
https://github.com/pandas-dev/pandas/issues/21471

### 辞書のlistからDataFrameを作ったとき、列の順番は保証されない
そもそも辞書型は順序が保証されないので、当然ではありますが。。。

```python
l = [{"b":1,"a":2}]
df = pd.DataFrame(l)
print(df.columns)
# Index(['a', 'b'], dtype='object')
```

### NaNが含まれているDataFrameを`to_csv`で出力すると、デフォルト空文字


```python
l = [{"b":1,"a":np.NaN}]
df = pd.DataFrame(l)
# NaNは空文字でCSV出力
df.to_csv("sample1.csv")
# NaNは0でCSV出力
df.to_csv("sample2.csv", na_rep=0)
```

```shell-session
$ less sample1.csv
,a,b
0,,1
$ less sample2.csv
,a,b
0,0,1
```

>na_rep : string, default ''
    Missing data representation


### Jupyter Notebookで最大業出力
https://qiita.com/daifuku_mochi2/items/30258e58750ff8e85d37

# Pytest

### 標準出力と標準エラー出力を表示する
`pytest -s`
https://pytest.readthedocs.io/en/reorganize-docs/new-docs/user/commandlineuseful.html#s-capture-no