---
# System prepended metadata

title: 技巧筆記
tags: [python, revisioned]

---

---
title: Python 常用技巧
dates: 2020-12-15
tags:
  - programming
  - python
---

# Python 技巧筆記

## 常見錯誤

* 函式呼叫時，**Python 會暫存參數當前的值**，而 C++ 不會，試著比較以下程式碼。
    ```cpp 
    #include <algorithm>
    #include <iostream>

    int x = 12;
    int func() {
        x += 1;
        return -100;
    }

    int main() {
        std::cout << std::max(x, func()) << std::endl;  // 13
    }
    ```
    ```python 
    x = 12
    def func():
        global x
        x += 1
        return -100

    print(max(x, func()))  # 12
    ```
    * 要不就是拿變數存 **`func()`** 結果再比較。
    * 要不就是把 **`x`** 放後面。
* **溢位檢查**，假設皆為正數。
    ```python 
    # 相加
    if a > INT_MAX - b: print('a + b overflows')
    # 相減
    if -a < INT_MIN - b: print('-(a + b) overflows')
    # 相乘
    if a > INT_MAX / b: print('a * b overflows')
    ```
    同樣概念，取平均值也不應該直接相加除以二。
    ```python 
    mid = low + (high - low) // 2
    ```




## 常用技巧

* 在 Python 的 **`(), [], {}`** 當中的換行都會被忽略，善用～
    ```python 
    if (COND1 and
        COND2 and
        COND3):
    ```

### Sequences

* Listcomps 執行效率並不輸於 **`map`** 和 **`filter`**，善用～
    ```python 
    beyond_ascii = [ord(char) for char in s if ord(s) > 127]
    beyond_ascii = [list(filter(lambda char: char > 127, map(ord, s)))]
    ```
* Genexp 相對節省記憶體，因為值是透過 iterator protocol 一個一個被產生，善用～
    * **`tuple(... for ...)`** 這叫作 generator expressions (*genexpr*)
    * **`[... for ...]`** 這才叫作 list comprehension (*listcomp*)
    * **`{chr(i) for ...}`** 這叫作 set comprehension (*setcomp*)
    * **`{k: v for ...}`** 這叫作 dict comprehension (*dictcomp*)
* 善用 **`min|max|sort|sorted`** 中的 **`key=`**
    ```python 
    # sort by values
    {k:v for k, v in sorted(DICT.items(), key=lambda item: item[1])}
    # sort by multiple factors
    LIST.sort(key=lambda item: (item[0], item[1], -len(item)))
    # min by string length
    MIN_STR = min(STRs, key=len)
    ```

#### **`zip()`**

* **`list(zip(*m))`** 轉置二維陣列。
* 二維陣列取 column。
    ```python
    list(zip(*m))[i]
    [row[i] for row in m]
    ```
    :::warning
    **`m[i][:]`** 同 **`m[:][i]`** 同 **`m[i]`** 為取 row。
    :::
* 根據 arr2 的值排序 arr1。
    ```python 
    zip_obj = zip(arr2, arr1)
    sorted(zip_obj)
    arr2, arr1 = zip(*zip_obj)
    ```



### Strings

#### **`format`** & f-string

```python 
print('"{:^10}""'.format('hahaha'))   # 置中
# "  hahaha  "
print('"{:<10.4}"'.format('hahaha'))  # 置左
# "haha      "
print('"{:>10.2f}"'.format(math.e))   # 置右
# "      2.72"
```

```python 
# Python 3.6 or above
print(f'"{"hahaha":^10}"')
print(f'"{"hahaha":<10.4}"')
print(f'"{math.e:>10.2f}"')
```


#### 移除字元

```python 
# 移除單一字元
s.replace(' ', '')
''.join(s.split(' '))

# 移除多個字元
''.join(re.split(' abc', s))

# 移除頭尾多字元
s.strip(' abc')
```

<!-- 6 intentional blank lines -->