# 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 ```