---
# System prepended metadata

title: with-as
tags: [語法相關]

---

with-as
===

`with` 適用於對資源進行存取的時機，使用 `with` 的話，檔案使用完之後就會自動關閉，也確保存取發生異常時，會執行後續的 error 操作。
EX：文件使用后自动关闭／线程中锁的自动获取和释放等。

雖然也可以透過以下 `try-except` 來達成一樣的目的，但比較冗長，還需要另外寫 `finally`：

```python=
try:
    f = open("１.txt")
except:
    print('fail to open')
    exit(-1)
finally:
    data = f.read()
    f.close()
```

而使用 `with` 的話，還能自動處理上下文環境產生的異常：
```python=
with open("１.txt") as f:
    data = f.read()
```

### 客製化 Context Manager

> context manager 用來管理 context（上下文）的，誕生的初衷就在於簡化 try-finally，因此就適合應用於在需要 finally 的地方，也就是需要清理的地方，比如
> 
> 保證資源的安全釋放，如 file、lock、semaphore、network connection 等
> 臨時操作的復原，如果一段邏輯有 setup、prepare，那麼就會對應 cleanup、teardown。
> [ref](https://www.cnblogs.com/xybaby/p/13202496.html)

若要自行建立 context manager，需要定義類別的 `__enter__` 與 `__exit__` 兩個方法。
* `with` 在開始執行時，會執行 `__enter__` 這個函數，傳回配給的資源（例如開啟的檔案）
* `with` 範圍結束時，會自動呼叫 `__exit__` 釋放資源（例如關閉檔案）。

以下是一個開檔的 context manager 範例：

```python=
#/usr/bin/python
# -*- coding: utf-8 -*-
# 自行定義 Context Manager
class File(object):
    def __init__(self, filename, mode):
        # 設定檔名與開檔模式
        self.filename = filename
        self.mode = mode

    # 配給資源（開啟檔案）
    def __enter__(self):
        print("開啟檔案：" + self.filename)
        self.open_file = open(self.filename, self.mode)
        return self.open_file

    # 回收資源（關閉檔案）
    def __exit__(self, type, value, traceback):
        print("關閉檔案：" + self.filename)
        self.open_file.close()
```

使用方式：

```python=
with File("file.txt", "w") as f:
    print("寫入檔案...")
    f.write("Hello, world.")
```

輸出
```
開啟檔案：file.txt
寫入檔案...
關閉檔案：file.txt
```

## Ref.
[Python 中 with用法及原理](https://blog.csdn.net/u012609509/article/details/72911564)
[Python 的 with 語法使用教學：Context Manager 資源管理器](https://blog.gtwang.org/programming/python-with-context-manager-tutorial/)

###### tags: `語法相關`