> For the complete documentation index, see [llms.txt](https://smallso.gitbook.io/stopwatch/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://smallso.gitbook.io/stopwatch/python/getting-started.md).

# 入门

## 指导 <a href="#guide" id="guide"></a>

当我们尝试计算一段程序的运行时间时，通常会使用 `timeit` 模块中定义的 `default_timer` 函数。

```python
current_timer_count: float = float(timeit.default_timer())
time.sleep(3)
print(float(timeit.default_timer()) - current_timer_count)
```

但在一些项目中，我们可能需要统计各个阶段的运行时间并统一管理和维护。此时，上文示例代码中演示的计算方式将非常不便。当需要计算的阶段节点过多时，将会产生大量重复的代码，造成代码冗余且不利于维护。

对于 Python 入门开发者而言，上文示例代码中演示的计算方式可能不利于理解。

在下文中，我们通过几段连续的 Python 代码片段来向您演示如何使用 Stopwatch 计算程序的运行时间。

### 导入模块 <a href="#import-module" id="import-module"></a>

为便于理解，我们需要使用 `time` 模块中的 `sleep` 函数来模拟程序的运行流程。

```python
import time
```

在使用 Stopwatch 之前，我们应该导入 `Stopwatch`：

```python
from stopwatch import Stopwatch
```

如果您需要捕获 Stopwatch 的相关异常，应该导入：

```python
from stopwatch import StatusError
from stopwatch import LapNameError
```

### 创建 Stopwatch <a href="#create-stopwatch" id="create-stopwatch"></a>

Stopwatch 的功能被定义在名为 `Stopwatch` 的类中。因此，我们可以通过实例化 `Stopwatch` 类来创建一个或多个 Stopwatch 实例。

```python
demo_stopwatch: Stopwatch = Stopwatch(
    default_precision = None
)
```

类 `Stopwatch` 的构造器方法包含一个数据类型为 `int` 的可选参数 `default_precision`，该参数指示被创建的 Stopwatch 实例的计时器精度（小数点位数）。如果未提供该参数或值为 `None`，则该参数的默认值为 `3`。

### 开始 Stopwatch <a href="#start-stopwatch" id="start-stopwatch"></a>

在上文中，我们定义了名为 `demo_stopwatch` 的变量，它是一个 Stopwatch 实例。现在我们尝试使 `demo_stopwatch` 开始计时。

```python
demo_stopwatch.start()
```

接着，我们使用 `time.sleep` 函数挂起当前线程 3 秒，模拟第一阶段的程序代码运行。

```python
time.sleep(3)
```

### 记录 Stopwatch <a href="#lap-stopwatch" id="lap-stopwatch"></a>

当我们的项目中存在多个程序阶段时，为了计算每个阶段的运行时间，阶段性计时是必不可少的。在上文示例代码中我们使用 `time.sleep` 函数模拟程序运行的第一个阶段，接着我们使用 `lap` 方法记录一次计时结果。

```python
lap_of_watch: float = demo_stopwatch.lap(
    lap_name = 'stage1'
)
```

计时记录分为 2 种：

* 命名计时记录
* 匿名计时记录

方法 `lap` 具有一个数据类型为 str 的可选参数 `lap_name`，该参数指示计时记录的唯一名称。如果未提供该参数或值为 `None`，则计时记录是匿名的。

该方法返回数据类型为 `float` 的返回值，其指示当前阶段的计时结果。如果这是第一条计时记录，计时结果是从 Stopwatch 开始计时到目前的间隔时间（秒）；否则，计时结果是从上一条计时记录到目前的间隔时间（秒）。

{% hint style="danger" %}
请注意，计时记录的名称在当前 Stopwatch 实例中必须是唯一的，即不可重复。否则，将引发 LapNameError 异常。
{% endhint %}

接着，我们再次使用 `time.sleep` 函数挂起当前线程 1 秒，模拟第二阶段的程序代码运行。

```python
time.sleep(1)
```

然后，记录第二阶段的计时结果。

```python
lap_of_watch: float = demo_stopwatch.lap(
    lap_name = 'stage2'
)
```

### 停止 Stopwatch <a href="#stop-stopwatch" id="stop-stopwatch"></a>

在上文中，我们使用 `time.sleep` 函数模拟了程序运行的第一阶段和第二阶段，并使用 `lap` 方法记录了程序运行第一阶段和第二阶段的计时结果。

现在，我们使 `demo_stopwatch` 停止计时。

```python
total_of_watch: float = demo_stopwatch.stop()
```

方法 `stop` 返回数据类型为 `float` 的返回值，其指示当前 Stopwatch 实例从首次开始计时到停止计时的总计时时间（秒）。

该返回值可以被忽略，我们可以使用 `get_watch` 方法即时检查 Stopwatch 实例的总计时时间：

```python
total_of_watch: float = demo_stopwatch.get_watch(
    watch_precision: int = None
)
```

方法 `get_watch` 有一个数据类型为 `int` 的可选参数，该参数指示获取的总计时精度（小数点）。如果未提供该参数或值为 `None`，该参数的默认值为 `Stopwatch` 类构造器方法参数 `default_precision` 的值。

{% hint style="danger" %}
请注意，在低于 0.1.3 版本的 Stopwatch 中使用 get\_watch 方法时，应该确保 Stopwatch 实例已经停止计时，否则将引发 StatusError 异常。
{% endhint %}

我们可以使用 `get_status` 方法检查当前 Stopwatch 实例的状态。

```python
if demo_stopwatch.get_status() == StopwatchStatus.Stopped:
    print('stopwatch has stopped timing')
```

`StopwatchStatus` 是预定义的 Stopwatch 状态枚举器，可以与方法 `get_status` 的返回值比较。

```python
from stopwatch import StopwatchStatus
```

### 获取 Stopwatch 记录 <a href="#get-laps" id="get-laps"></a>

在上文中，我们使用 `lap` 方法分阶段记录了程序运行第一阶段和第二阶段的计时结果。现在我们尝试获取这些计时记录。

#### 获取命名计时记录

我们可以使用 `get_lap` 方法获取命名的计时记录。

```python
lap_of_watch: float = demo_stopwatch.get_lap(
    lap_name = 'stage1', 
    lap_precision = 3
)
```

方法 `get_lap` 有 2 个参数，它们分别是：

| 参数名            | 数据类型 | 可选    | 描述               |
| -------------- | ---- | ----- | ---------------- |
| lap\_name      | str  | False | 计时记录的唯一名称。       |
| lap\_precision | int  | True  | 获取的计时记录精度（小数点位数） |

参数 `lap_precision` 是可选的。如果未提供该参数或值为 `None`，该参数的默认值为 `Stopwatch` 类构造器方法参数 `default_precision` 的值。

{% hint style="danger" %}
请注意，如果指定计时记录名称不存在，将引发 LapNameError 异常。
{% endhint %}

如果我们需要确定一个计时记录是否存在，可以使用 `has_lap` 方法检查。

```python
if not demo_stopwatch.has_lap(
    lap_name = 'stage1'
):
    print('no such lap')
```

#### 获取匿名计时记录

值得注意的是，匿名计时记录并非是真正的匿名，而是使用 `lap_` 和记录编号组合的方式来命名计时记录（例如：`lap_1`）。因此，我们也可以使用 `get_lap` 方法获取匿名计时记录，但更便捷的方式是使用 `get_lap_by_number` 方法。

```python
lap_of_watch: float = demo_stopwatch.get_lap_by_number(
    lap_number = 1, 
    lap_precision = 3
)
```

与方法 `get_lap` 不同之处是，该方法的参数 `lap_number` 指示匿名记录的编号（从 1 开始），其数据类型为 `int`。在该方法内部仍然调用 `get_lap` 方法获取匿名计时记录。

{% hint style="danger" %}
请注意，如果使用该方法获取非匿名计时记录，将引发 LapNameError 异常。
{% endhint %}

为使您更加清晰的了解命名计时记录与匿名计时记录之间的关系，我们将通过下文的演示来详细说明。

```python
demo_stopwatch.lap('stage1')
demo_stopwatch.lap()
demo_stopwatch.get_lap_by_number(1)
```

在上文示例代码中，我们记录了 2 次 Stopwatch 当前计时结果，命名计时记录和匿名计时记录各一条。现在 Stopwatch 实例中计时记录集的内容如下：

```python
[
    'stage1', 
    'lap_2'
]
```

而在上文示例代码中，使用 `get_lap_by_number` 方法获取第一条命名计时记录时将引发异常：

```
LapNameError(no such lap: lap_1)
```

因为当前 Stopwatch 实例的计时记录集中不存在名为 `lap_1` 的命名计时记录，所以必然引发 `LapNameError` 异常。由此可见匿名计时记录仅是以默认形式（`lap_` 和记录编号的组合）对记录命名。

#### 获取所有计时记录的平均结果

如果我们需要获取当前 Stopwatch 实例中所有计时记录的平均计时结果，可以使用 `get_average_of_laps` 方法。

```python
average_of_laps: float = demo_stopwatch.get_average_of_laps(
    average_precision = None
)
```

方法 `get_average_of_laps` 有一个数据类型为 `int` 的可选参数 `average_precision`，该参数指示获取的计时记录平均结果的精度（小数点位数）。如果未提供该参数或值为 `None`，该方法的行为与 `get_lap` 一致。

#### 枚举所有计时记录名称

我们还可以使用 `get_laps` 方法枚举所有计时记录的唯一名称，其中也包含匿名计时记录。

```python
for lap_name in demo_stopwatch.get_laps():
    print(lap_name)
```

方法 `get_laps` 返回数据类型为 `list` 的返回值，其中包含所有计时记录的唯一名称，成员数据类型为 `str`。

#### 获取计时记录条数

我们可以使用 `get_lap_count` 方法获取当前 Stopwatch 实例的计时记录总条数。

```python
number_of_laps: int = demo_stopwatch.get_lap_count()
```

### 重置 Stopwatch <a href="#reset-stopwatch" id="reset-stopwatch"></a>

每个 Stopwatch 实例自开始计时起，都会产生当前实例的状态数据（例如：计时记录等...）。如果我们需要清空这些数据，则应该将 Stopwatch 实例重置为初始状态。

> **Tips**: Stopwatch 实例可以重复开始和结束，计时记录和总计时时长都将累计，直到被重置。

```python
demo_stopwatch.reset()
```

重置 Stopwatch 实例后，所有状态数据将被清理，Stopwatch 实例重置为初始状态。

{% hint style="danger" %}
请注意，如果 Stopwatch 实例仍然处于计时状态，将引发 StatusError 异常。可以使用 get\_status 方法检查 Stopwatch 实例的状态。
{% endhint %}

## 示例 <a href="#demo" id="demo"></a>

下文将以完整的 Python 示例代码演示如何使用 Stopwatch。

### 源代码 <a href="#source" id="source"></a>

{% code title="quickstart.py" %}

```python
# quickstart.py is python-3.7.4 source file

import time

from stopwatch import Stopwatch
from stopwatch import StopwatchStatus


# define main function

def main():

    # instantiate stopwatch

    demo_stopwatch: Stopwatch = Stopwatch(
        default_precision = 3   # ignorable
    )

    # make stopwatch start timing
    
    demo_stopwatch.start()

    # the first stage of the simulation program

    time.sleep(3)

    # it takes time to record the first phase of the program

    demo_stopwatch.lap('stage1')

    # the second stage of the simulation program

    time.sleep(1)

    # it takes time to record the second phase of the program

    demo_stopwatch.lap('stage2')

    # try checking the stopwatch total time every 1 second

    for count in range(3):
        print('{COUNT} check: {WATCH_SECONDS} seconds'.format(
            COUNT = count + 1, 
            WATCH_SECONDS = demo_stopwatch.get_watch()
        ))

    # record cycle check time spent on stopwatch

    demo_stopwatch.lap('stage3')

    # get the status of stopwatch

    if demo_stopwatch.get_status() == StopwatchStatus.Started:
        print('stopwatch is timing...')

    # stop and print the timing of the stopwatch
    
    print(
        (
            'total: {TOTAL_SECONDS} seconds\n'
            'stage1: {STAGE1_SECONDS} seconds\n'
            'stage2: {STAGE2_SECONDS} seconds\n'
            'stage3: {STAGE3_SECONDS} seconds\n'
            '----------\n'
            'average of stages: {AVERAGE_SECONDS} seconds'
        ).format(
            TOTAL_SECONDS = demo_stopwatch.stop(), 
            STAGE1_SECONDS = demo_stopwatch.get_lap('stage1'), 
            STAGE2_SECONDS = demo_stopwatch.get_lap('stage2'), 
            STAGE3_SECONDS = demo_stopwatch.get_lap('stage2'), 
            AVERAGE_SECONDS = demo_stopwatch.get_average_of_laps()
        )
    )

    # reset stopwatch

    demo_stopwatch.reset()


# define virtual main function

if __name__ == '__main__':
    main()
```

{% endcode %}

### 运行结果 <a href="#result" id="result"></a>

```bash
1 check: 4.001 seconds
2 check: 4.002 seconds
3 check: 4.003 seconds
stopwatch is timing...
total: 4.006 seconds
stage1: 3.0 seconds
stage2: 1.001 seconds
stage3: 1.001 seconds
----------
average of stages: 1.335 seconds
```
