小白的Python學習筆記(十四)面向對象編程知識總結《4》

使用attrs解放雙手

你們好,這一期我想和你們分享一個OOP編程的高效神器:attrs庫python

首先咱們來介紹下 attrs 這個庫,其官方的介紹以下:git

attrs 是這樣的一個 Python 工具包,它能將你從繁綜複雜的實現上解脫出來,享受編寫 Python 類的快樂。它的目標就是在不減慢你編程速度的前提下,幫助你來編寫簡潔而又正確的代碼。github

所以用了它,定義和實現 Python 類變得更加簡潔和高效編程

首先明確一點,咱們如今是裝了 attrs 和 cattrs 這兩個庫,可是實際導入的時候是使用 attr 和 cattr 這兩個包,是不帶 s 的。app

在 attr 這個庫裏面有兩個比較經常使用的組件叫作 attrs 和 attr,前者是主要用來修飾一個自定義類的,後者是定義類裏面的一個字段的。下面是一個小例子less

from attr import attrs,attrib

@attrs
class Person:
    name = attrib(type = str,default="")
    age = attrib(type = int,default=0)
    sex = attrib(type = str,default="")

if __name__ == '__main__':
    first_person = Person("John",18,"M")
    print(first_person)

Out:Person(name='John', age=18, sex='M')


複製代碼

主要做用

能夠發現,Person這個類 三個屬性都只寫了一次,同時還指定了各個字段的類型和默認值,另外也不須要再定義 init 方法和 repr 方法了,很是簡潔工具

實際上,主要是 attrs 這個修飾符起了做用,而後根據定義的 attrib 屬性自動幫咱們實現了 initrepreqneltlegtgehash 這幾個方法spa

深刻了解

如今來用實例看一下:code

first_person = Person("John",18,"M")
second_person = Person("Nancy",16,"F")

print('Equal:', first_person == second_person)  #False
print('Not Equal(ne):', first_person != second_person) #True
print('Less Than(lt):', first_person.age < second_person.age) #False
print('Less or Equal(le):', first_person.age <= second_person.age) #False
print('Greater Than(gt):', first_person.age > second_person.age) #True
print('Greater or Equal(ge):', first_person.age >= second_person.age) #True
複製代碼

屬性定義

對於 attrib 的定義,能夠傳入各類參數,不一樣的參數對於這個類的定義有很是大的影響。對象

下面來詳細瞭解一下每一個屬性的具體參數和用法。

首先咱們用 attrs 裏面的 fields 方法能夠查看一下

from attr import attrs, attrib,fields
print(fields(Person))

(Attribute(name='name', default='', validator=None, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=<class 'str'>, converter=None, kw_only=False), Attribute(name='age', default=0, validator=None, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=<class 'int'>, converter=None, kw_only=False), Attribute(name='sex', default='', validator=None, repr=True, cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=<class 'str'>, converter=None, kw_only=False))

複製代碼
參數 解釋
name 屬性的名字,是一個字符串類型
default 屬性的默認值,若是沒有傳入初始化數據,那麼就會使用默認值,若是沒有默認值定義,那麼就是 NOTHING,即沒有默認值
validator 驗證器,檢查傳入的參數是否合法
init 是否參與初始化,若是爲 False,那麼這個參數不能當作類的初始化參數,默認是 True。
type 類型,好比 int、str 等各類類型,默認爲 None
metadata 元數據,只讀性的附加數據
converter 轉換器,進行一些值的處理和轉換器,增長容錯性
kw_only 是否爲強制關鍵字參數,默認爲 False

初始化

若是一個類的某些屬性不想參與初始化,好比想直接設置一個初始值,一直固定不變,咱們能夠將屬性的 init 參數設置爲 False,看一個實例:

from attr import attrs,attrib

@attrs
class Person:
    name = attrib(type = str)
    age = attrib(init=False)
    sex = attrib(type = str)

first = Person("John","M") # Person(name='John', age=NOTHING, sex='M')

second = Person("Mike",89,"M")
#TypeError: __init__() takes 3 positional arguments but 4 were given
複製代碼

能夠發現,first沒有問題,可是second會報錯,由於age沒有參與初始化,只剩了self,age,sex

強制關鍵字

強制關鍵字是 Python 裏面的一個特性,在傳入的時候必須使用關鍵字的名字來傳入

設置了強制關鍵字參數的屬性必需要放在後面,其後面不能再有非強制關鍵字參數的屬性

咱們仍是拿同樣的例子,這回把sex的參數

from attr import attrs,attrib

@attrs
class Person:
    name = attrib(type = str)
    age = attrib(type = str)
    sex = attrib(kw_only=True)
    
first = Person("John",18,sex="M")
#Person(name='John', age=18, sex='M')

複製代碼

若是初始化first時使用Person("John",18,"M")則會報錯

驗證器

有時候在設置一個屬性的時候必需要知足某個條件,好比性別必需要是男或者女,不然就不合法。對於這種狀況,咱們就須要有條件來控制某些屬性不能爲非法值。

from attr import attrs, attrib

def is_valid_gender(instance, attribute, value):
    if value not in ('M', 'F'):
        raise ValueError(f'gender {value} is not valid')
        
@attrs
class Person:
    name = attrib(type = str)
    age = attrib(type = str)
    sex = attrib(validator=is_valid_gender)
複製代碼

在這裏咱們定義了一個驗證器 Validator 方法,叫作 is_valid_gender,其中 gender 定義的時候傳入了一個參數 validator,其值就是咱們定義的 Validator 方法:

  • instance:類對象
  • attribute:屬性名
  • value:屬性值

下面作了兩個實驗,一個就是正常傳入 "M",另外一個寫錯了,寫的是 "X":

first = Person("John",18,"M")  
# Person(name='John', age=18, sex='M')

second = Person("Ann",29,"X")  
ValueError: gender X is not valid
複製代碼

second報錯了,由於其值不是正常的性別,因此程序直接報錯終止 注意在 Validator 裏面返回 True 或 False 是沒用的,錯誤的值還會被照常複製。因此,必定要在 Validator 裏面 raise 某個錯誤。

另外 attrs 庫裏面還給咱們內置了好多 Validator,好比判斷類型,這裏若是規定age必須爲 int 類型:

age  =attrib(validator=validators.instance_of(int))
複製代碼

另外 validator 參數還支持多個 Validator,好比咱們要設置既要是數字,又要小於 100,那麼能夠把幾個 Validator 放到一個列表裏面並傳入:

from attr import attrs, attrib,validators

def is_valid_gender(instance, attribute, value):
    if value not in ('M', 'F'):
        raise ValueError(f'gender {value} is not valid')
        
def is_less_than_100(instance, attribute, value):
    if value > 100:
        raise ValueError(f'age {value} must less than 100')
        
@attrs
class Person:
    name = attrib(type = str)
    age = attrib(validator=[validators.instance_of(int), is_less_than_100])
    sex = attrib(validator=[validators.instance_of(str),is_valid_gender])


複製代碼

轉換器

不少時候咱們會不當心傳入一些形式不太標準的結果,好比原本是 int 類型的 100,咱們傳入了字符串類型的 100,那這時候直接拋錯應該很差吧,因此咱們能夠設置一些轉換器來加強容錯機制,好比將字符串自動轉爲數字:

from attr import attrs, attrib,validators

def to_int(value):
    try:
        return int(value)
    except:
        return None
@attrs
class Person:
    name = attrib(type = str)
    age = attrib(converter=to_int)
    sex = attrib(validator=validators.instance_of(str))

last_person = Person("xiaobai","35","M")    
print(last_person)

Out: Person(name='xiaobai', age=35, sex='M')
複製代碼

總結

此次我記錄了attrs 庫的用法,是參考了別人的文章,個人其餘原創文章已經放到了Github上,若是感興趣的朋友能夠去看看,連接以下:

相關文章
相關標籤/搜索