Python描述符的使用 前言 作為一位python的使用者,你可能使用python有一段時間了,但是對於python中的描述符卻未必使用過,接下來是對描述符使用的介紹 場景介紹 為了引入描述符的使用,我們先設計一個非常簡單的類: class Product(): def __init__(self ...
Python描述符的使用
前言
作為一位python的使用者,你可能使用python有一段時間了,但是對於python中的描述符卻未必使用過,接下來是對描述符使用的介紹
場景介紹
為了引入描述符的使用,我們先設計一個非常簡單的類:
class Product():
def __init__(self,name,quantity,price):
self.name = name
self.quantity = quantity
self.price = price
這是一個商品類,存儲該商品的名稱,數量與價格。
對於一件商品,我們一般會期望它的數量和價格不會是負值,為了避免這種情況,我們可以在初始化的時候加一些判斷,比如下麵這樣:
class Product():
def __init__(self,name,quantity,price):
self.name = name
if quantity<0:
raise ValueError('quantity must be >= 0')
self.quantity = quantity
if quantity<0:
raise ValueError('price must be >= 0')
self.price = price
但是這樣還會有一個弊端就是這樣的判斷只是加在了初始化的時候,然後在之後對類的實例的屬性進行賦值的時候還是無法保證賦的值是大於0 的
於是我們可以使用‘特性’來解決這個問題:
class Product():
def __init__(self,name,quantity,price):
self.name = name
self.quantity = quantity
self.price = price
@property
def quantity(self):
return self._quantity
@quantity.setter
def quantity(self,value):
if value < 0:
raise ValueError('quantity must be >= 0')
else:
self._quantity = value
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError('price must be >= 0')
else:
self._price = value
book = Product('mybook',6,30)
print(book.quantity)
這裡的@property和@quantity.setter是兩個裝飾器,它可以設置屬性的讀與寫,就相當於讀寫屬性,但其實是執行一個函數,具體有關特性的介紹,可以再自行查找,這裡主要是為了引出描述符。
通過特性,可以完成為屬性賦值時添加判斷。但是當一個類中有更多的屬性,很多屬性同樣需要添加非負數賦值的檢查的時候,使用特性這種方式就會顯得過於累贅,會有很多的代碼重覆,也會添加很多裝飾器,這時就可以使用描述符來解決這個問題。
使用描述符
首先看一下描述符的概念
描述符就是一個“綁定行為“的對象屬性,在描述符協議中,它可以通過方法充寫屬性的訪問。這些方法有get(),set(),delete().如果這些方法中任何一個被定義在一個對象中,這個對象就是一個描述符
(這幾個方法是特殊方法,雙下劃線由於轉換未顯示)
我們先把上文中的商品類按照使用描述符進行修改:
class NotNegative():
def __init__(self,name):
self.name = name
def __set__(self, instance, value):
if value < 0:
raise ValueError(self.name+' must be >= 0')
else:
instance.__dict__[self.name] = value
class Product():
quantity = NotNegative('quantity')
price = NotNegative('price')
def __init__(self,name,quantity,price):
self.name = name
self.quantity = quantity
self.price = price
book = Product('mybook',2,5)
NotNegative是描述符類,它是Product類的類屬性
在該例子中,如果執行book.quantity=3,解釋器會先查找實例屬性,發現有quantity屬性,但是解釋器又發現同樣有一個類屬性是描述符,於是解釋器最終會選擇走描述符這條路。然後因為是描述符,於是會執行描述符中的set特殊方法。相關屬性的查找順序可以參考https://www.cnblogs.com/Jimmy1988/p/6808237.html
描述符中的set特殊方法的參數有為
-
self :是描述符實例
-
instance :是相當於例子中的實例book
-
value :就是要賦予的值
由於這些屬性對於取值沒有什麼特殊的要求所以例子中沒有實現get特殊方法。
get方法同樣有3個參數self, instance, owner。self,instance與set中的相同,owner為例子中的Product類
接下來主要看一下描述符set方法中else部分進行的操作
instance.__dict__[self.name] = value
通過調用book實例的dict,直接為dict中的屬性賦值,這也是參數中傳入實例的一個重要原因。由於描述符對象是作為類屬性存在,所以可能會有很多個該類的對象訪問,為了防止屬性的覆蓋,直接存入實例的屬性中是妥當的。但這裡不能為屬性賦值的方式,不然就會陷入死迴圈當中。
對於數據描述符與非數據描述符,一個類,如果只定義了 get() 方法,而沒有定義 set(), delete() 方法,則認為是非數據描述符; 反之,則成為數據描述符。
最後,本文是對描述符的使用做了簡單的介紹與講解,如需更加深入瞭解可以參考《流暢的Python》屬性描述符部分
-
今天我們將介紹mode屬性的development值。它會自動為你配置Webpack以簡化開發過程。除此之外,我們還會介紹webpack-dev-server——包括模塊熱替換。開始吧! ...
-
這個主要是自己遇到很多次了,每次都去網上查改哪裡,這次記到自己這裡吧,以後把遇到的vue工具的一些問題都整理到這裡 在vue中開發的項目有時候需要到手機上看效果,但是你配好本地埠之後,會出現訪問內容 Invalid Host header 這時候需要在 webpack-dev.config.js中 ...
-
1.傳統方式 >原型鏈 (過多繼承了沒用的屬性) Grand.prototype.lastname = 'zhang' function Grand(); } var grand = new Grand(); Father.prototype = grand; function Father(){ ...
-
什麼是BOM? bom即browser object model 也就是瀏覽器對象模型,BOM由多個對象組成,其中代表瀏覽器視窗的window對象是BOM的頂層對象,其他對象都是該對象的子對象。 頂層對象:window 子對象:location:location 對象包含有關當前 URL 的信息; ...
-
概述 Prometheus的主要特點 組件 結構圖 適用場景 不適用場景 安裝node_exporter,系統性能指數收集(收集系統性能情況) 下載文件 解壓並複製node_exporter應用程式到/usr/local/bin 清理下載的文件和解壓的文件夾 添加自啟動服務 添加服務配置文件 寫入配 ...
-
都說三十而立,但現在三十成了程式員的一道坎,如果近年來你有過求職的經歷,或是你關註過智聯、前程、獵聘等招聘平臺,你會發現平臺上數以萬計的招聘信息都會要求應聘者年齡在35歲以內,對於部分科技類初創企業,公司寧願放寬教育程度的要求。也就是說,如果你的年齡大於30歲,那就不要費神來申請了,因為你很可能在自 ...
-
一、什麼是面向對象 在用面向對象思想寫代碼之前,先瞭解一下什麼是面向對象? 個人理解: 面向對象:把現實世界里的具體物體或者邏輯世界的邏輯物體,用抽象手段,把這些物體抽象成程式能夠識別的類,使類具備物體的屬性和行為,把物體與物體之間的關聯轉換成類與類之間的關聯,用編程邏輯把這些關聯表示出來設計成程式 ...
-
import java.util.Scanner;public class Main{public static void main(String[] args) {int maxn=1000000+5;int mod=10007;int[] Fibonacci=new int[maxn];Fibo ...