Python中使用Type hinting 和 annotations

Type hints最大的好處就是易於代碼維護。當新成員加入,想要貢獻代碼時,能減小不少時間。
也方便咱們在調用漢書時提供了錯誤的類型傳遞致使運行時錯誤的檢測。html

第一個類型註解示例

咱們使用一個簡單例子,兩個整數相加。python

def add(a, b):
    return a + b

上面的例子,可工做於任意能夠進行+操做符的對象。若是咱們僅讓該函數只能對整型做爲參數,而後也只是返回整型結果呢?express

def add(a: int, b: int) -> int:
    return a + b

咱們注意到,返回類型是在函數定義末尾使用 -> 符號來指明。函數

使用mypi及更多例子

Mypy是爲Python構建的靜態類型檢查器。若是咱們使用上面的類型註解,mypy能夠在代碼中
幫咱們找到一些錯誤。你可使用在開發流程中任意階段使用它,好比是在CI中做適當的測試。學習

安裝mypy

咱們在虛擬環境中安裝mypy測試

$ pip install mypy

咱們的示例

咱們會進行以下示例描述,雖然代碼做用不大,可是咱們能夠經過它來學習類型註解以及mypy.code

class Student:

    def __init__(self, name, batch, branch, roll):
        self.name = name
        self.batch = batch
        self.branch = branch
        self.roll = roll
        self.semester = None
        self.papers = {}

    def is_passed(self):
        "To find if the student has pass the exam in the current semester"
        for k, v in self.papers.items():
            if v < 34:
                return False

        return True


    def total_score(self):
        "Returns the total score of the student"
        total = 0
        for k, v in self.papers.items():
            total += v

        return total


std1 = Student("Kushal", 2005, "cse", "123")
std2 = Student("Sayan", 2005, "cse", 121)
std3 = Student("Anwesha", 2005, "law", 122)

std1.papers = {"english": 78, "math": 82, "science": 77}
std2.papers = {"english": 80, "math": 92, "science": "78"}
std3.papers = {"english": 82, "math": 87, "science": 77}

for std in [std1, std2, std3]:
    print("Passed: {0}. The toral score of {1} is {2}".format(std.is_passed(), std.name, std.total_score()))

你可能發現了代碼中其實有錯誤,可是在實際開發過程咱們常常會發生,而且除了在運行時發現,咱們並無其餘更好的機制。orm

使用 mypy

咱們經過mypy來執行咱們的代碼,咱們把文件取名爲students2.pyhtm

加入一些類型註解

咱們將會在__init__方法中加入一些類型註解。爲減小代碼長度,修改以下:對象

class Student:

    def __init__(self, name: str, batch: int, branch: str, roll: int) -> None:
        self.name = name
        self.batch = batch
        self.branch = branch
        self.roll = roll
        self.semester = None
        self.papers = {}

$ mypy students2.py 
students2.py:9: error: Need type annotation for 'papers'
students2.py:29: error: Argument 4 to "Student" has incompatible type "str"; expected "int"

能夠看到mypy有提示哪些變量沒有類型註解,還有在29行,參數咱們指望的是整型,但在調用時傳遞了字符串類型,如今讓咱們來修正他。

from typing import Dict

class Student:

    def __init__(self, name: str, batch: int, branch: str, roll: int) -> None:
        self.name = name
        self.batch = batch
        self.branch = branch
        self.roll = roll
        self.semester = None
        self.papers: Dict[str, int] = {}

    def is_passed(self):
        "To find if the student has pass the exam in the current semester"
        for k, v in self.papers.items():
            if v < 34:
                return False

        return True


    def total_score(self):
        "Returns the total score of the student"
        total = 0
        for k, v in self.papers.items():
            total += v

        return total


std1: Student = Student("Kushal", 2005, "cse", 123)
std2: Student = Student("Sayan", 2005, "cse", 121)
std3: Student = Student("Anwesha", 2005, "law", 122)

std1.papers = {"english": 78, "math": 82, "science": 77}
std2.papers = {"english": 80, "math": 92, "science": 78}
std3.papers = {"english": 82, "math": 87, "science": 77}

for std in [std1, std2, std3]:
    print("Passed: {0}. The toral score of {1} is {2}".format(std.is_passed(), std.name, std.total_score()))

如今,沒有任何錯誤了。在第一行咱們還從typing包引入了Dcit。並做爲了self.paper的類型註解,這裏的意思就是該變量是字典類型,使用字符串做爲鍵,整型做爲值。咱們設置std1, std2和std3變量註解爲Student類。

如今,咱們給papers變量賦一些錯誤類型的值。

std1.papers = ["English", "Math"]

或者錯誤的字典鍵值對

std2.papers = {1: "Engish", 2: "Math"}

咱們能看到相似以下錯誤

$ mypy students2.py
students2.py:35: error: Incompatible types in assignment (expression has type List[str], variable has type Dict[str, int])
students2.py:36: error: Dict entry 0 has incompatible type "int": "str"
students2.py:36: error: Dict entry 1 has incompatible type "int": "str"

更多類型註解示例

from typing import List, Tuple, Sequence, Optional

values: List[int] = []
city: int = 350 # The city code, not a name


# This function returns a Tuple of two values, a str and an int
def get_details() -> Tuple[str, int]:
    return "Python", 5

# The following is an example of Tuple unpacking
name: str
marks: int
name, marks = get_details()


def print_all(values: Sequence) -> None:
    for v in values:
        print(v)


print_all([1,2,3])
print_all({"name": "kushal", "class": 5})
# alltypes.py:23: error: Argument 1 to "print_all" has incompatible type Dict[str, object]; expected Sequence[Any]
# But running the code will give us no error with wrong output

def add_ten(number: Optional[int] = None) -> int:
    if number:
        return number + 10
    else:
        return 42

print(add_ten())
print(add_ten(12))

你能夠從PEP 484瞭解更多類型。typing模塊進行更多例子解釋如何在代碼中使用類型註解。

相關文章
相關標籤/搜索