# Section 64~70
## 65 Code Metrics
Cyclomatic complexity
- Radon 氡
- cc
[Introduction to Code Metrics](https://radon.readthedocs.io/en/latest/intro.html)
```radon cc -s```
- raw
選能理解的metrics
- Xenon 氙
- [mccabe](https://pypi.org/project/mccabe/)
## 66. Typing 1 (type hints, autocompletion, static vs dynamic type checking)
- https://realpython.com/videos/dynamic-vs-static/
Python 是動態型別(Dynamic Typing)語言,變數的型別是在程式執行時才決定。
```python=
x = 10 # int
x = "Hello" # str
x = [1, 2] # list
```
- Duck Typing 概念是注重物件擁有的方法或屬性,而不是它的類型或所屬類別。
https://zhuanlan.zhihu.com/p/489207162
## 67. Typing 2 (Mypy and basic typing)
- PEP 484 提出型別提示(Type Hints),提高可讀性/可維護性,並允許開發者顯式標註變數的型別
```pythn=
x: int = 10
name: str = "Hi"
```
- mypy
- code
```python=
# example.py
def add(a: int, b: int) -> int:
return a + b
result = add(5, 10)
result2 = add("5", 10)
```
- output
```python=
example.py:9: error: Argument 1 to "add" has incompatible type "str"; expected "int"
```
## 68. Typing 3 (Simple and Complex Types)
- [mypy doc](https://mypy.readthedocs.io/en/stable/)
- [typing](https://docs.python.org/3/library/typing.html)
## 69. Typing 4 (Union and Optional)
- Union
- 值可以是多種不同類型
```python=
from typing import Union
def add(a: Union[int, float], b: Union[int, float]) -> Union[int, float]:
return a + b
print(add(2, 3)) # 5
print(add(2.5, 3.5)) # 6.0
```
- Optional
- 值可以是某種類型,也可是None。```Optional[X]``` 等同 ```Union[X, None]```
```python=
from typing import Optional
def greet(name: Optional[str]) -> str:
if name is None:
return "Hello, Stranger!"
return f"Hello, {name}!"
print(greet("ABC")) # Hello, ABC!
print(greet(None)) # Hello, Stranger!
```
## 70. Typing 5 (TypedDict, dataclasses, NamedTuple, self-referential types)
- TypedDict
- 具有固定key,對應型別的dictionary
```python=
from typing import TypedDict
class Person(TypedDict):
name: str
age: int
email: str
# 使用範例
person: Person = {
"name": "ABC",
"age": 30,
"email": "ABC@gmail.com"
}
print(person["name"])
```
- 固定的鍵
```python=
Dict[str, Union[str, int]]
```
- dataclasses
- use dataclasses
```python=
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
email: str
# 使用範例
person = Person(name="ABC", age=30, email="ABC@gmail.com")
```
- without dataclasses
```python=
class Person:
def __init__(self, name: str, age: int, email: str):
self.name = name
self.age = age
self.email = email
def __repr__(self):
return f"Person(name='{self.name}', age={self.age}, email='{self.email}')"
person = Person(name="ABC", age=30, email="ABC@gmail.com")
``````
- ```from __future__ import annotations``` 延遲解析
- Python 3.9
- Error
```python=
from typing import Optional
class A:
def __init__(self, other: Optional[A] = None):
self.other = other
```
```python=
NameError: name 'A' is not defined
```
- Use ```from __future__ import annotations```
```python=
from __future__ import annotations
from typing import Optional
class A:
def __init__(self, other: Optional[A] = None):
self.other = other
```
- Python 3.10 +
- [PEP 604](https://docs.python.org/3/whatsnew/3.10.html)
```python=
class A:
def __init__(self, other: A | None = None):
self.other = other
```