电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Python 從attribute到property詳解

瀏覽:38日期:2022-08-04 08:30:59

字面意思上的區別

Attribute與property, 都可翻譯成屬性. 雖然無論是在中文中還是英文中 它們的意思都幾乎一樣, 但仍有些許差別. Google了好幾下, 找到了一個看起來比較靠譜的解釋:

According to Webster, a property is a characteristic that belongs to a thing’s essential nature and may be used to describe a type or species.

An attribute is a modifier word that serves to limit, identify, particularize, describe, or supplement the meaning of the word it modifies.

簡單來說, property是類的本質屬性, 可用于定義和描述一個類別或物種; attribute則是用于詳細說明它所描述的物體, 是物體的具體屬性.

例如: 人都有嘴巴. 有的人嘴巴很大, 嘴巴是人的property之一, 而大嘴巴只能說是部分人的attribute.

從這個意義上講, property是attribute的子集.

Python里的attribute與property

回到Python.

Attribute與property在Java中不作區分, 但在Python中有所不同. 下面是Fluent Python(Chapter 19)給出的(非正式)定義:

Python 從attribute到property詳解

接下來分別解釋.

attribute

所有的數據屬性(data attribute)與方法(method)都是attribute. 根據attribute的所有者, 可分為class attribute與instance attribute. class或instance的所有attribute都存儲在各自的__dict__屬性中.

例如:

# Python3class Foo(): name = ’Foo class attribute’ def fn(self): passprint(’class attribute:’, Foo.__dict__)print()foo = Foo()foo.name = ’foo instance attribute’print(’instance attribute:’, foo.__dict__)

輸出:

class attribute: {’fn’: <function Foo.fn at 0x7fd135ec8ea0>, ... , ’name’: ’Foo class attribute’}

instance attribute: {’name’: ’foo instance attribute’}

property

property是出于安全考慮用setter/getter方法替代data attribute, 例如, 只讀屬性與屬性值合法性驗證.

只讀屬性

例如:

class Foo(): def __init__(self, name): self.name = namefoo = Foo(’I do not want to be changed’)print(’foo.name = ’, foo.name)foo.name = ’Unluckily, I can be changed’print(’foo.name = ’, foo.name)

輸出:

foo.name = I do not want to be changedfoo.name = Unluckily, I can be changed

在上面的代碼中, 假如我們只想將foo的name屬性暴露給外部讀取, 但并不想它被修改, 我們該怎么辦? 之前在Python 定義只讀屬性中列出了兩種解決方案. 第一種方案:”通過私有屬性”, 其實就是用property替代attribute.

將上面的foo.name改寫成property:

class Foo(): def __init__(self, name): self.__name = name @property def name(self): return self.__namefoo = Foo(’I do not want to be changed’)print(’foo.name = ’, foo.name)foo.name = ’Luckily, I really can not be changed’

輸出:

foo.name = I do not want to be changed---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-69-101c96ba497e> in <module>() 9 foo = Foo(’I do not want to be changed’) 10 print(’foo.name = ’, foo.name)---> 11 foo.name = ’Luckily, I really can not be changed’AttributeError: can’t set attribute

有兩點需要注意:

foo.name確實已經不能通過foo.name = ...來修改了, 即, foo.name已經是只讀屬性.

將foo.name從attribute變成property之后, 它的訪問方式并沒有改變. 也就是說, 對外接口沒有改變. 這個優點可以讓我們從容的寫代碼, 不用在一開始就糾結于是使用property還是attribute, 因為可以都使用attribute, 如果有需要, 以后可以在不影響外部代碼的前提下隨時修改. 而在Java里要做到這一點很難(如果可以做到的話).

屬性值合法性驗證

在上面的例子中, foo.name只有getter方法, 是只讀的, 但其實property也是可修改的, 只需要為它添加一個setter方法就行了. 那么問題就來了, 如果property也是可讀可改, 那為何要費事將attribute改寫成property呢?

想象一個簡單的購物相關的業務場景. 一個Item代表用戶購買的一樣東西, 主要有類別, 價格和數量屬性:

class Item(): def __init__(self, category, count, price): self.cat = category self.count = count self.price = price

正常的調用是類似于這樣的, 價格與數量都是正數:

item = Item(’Bread’, 1, 10)

可是, 若價格或數量設置為負數也不會報錯:

item.price = -10item.count = -1invalid_item1 = Item(’Bread’, -1, 10)invalid_item2 = Item(’Bread’, 1, -10)

從語法上看, 這些語句都是合法的, 但從業務上看, 它們都是不合法的. 那么, 怎樣才能防止這種非法賦值呢? 一種解決方案是按照Java風格, 實現一個Java式的setter方法, 通過item.set_price(price)設置price屬性, 然后在set_price方法里寫驗證代碼. 這樣是可行的, 但不夠Pythonic. Python的風格是讀與寫都通過屬性名進行:

print(item.price)item.price = -10

這樣做的好處之前提到過: 將attribute改寫成property時不會改變對外接口. 那么, 如何在執行item.price = -10時檢驗-10的合法性呢? 最直白的方法是在__setattr__方法里設置攔截, 但很麻煩, 特別是當需要驗證的屬性很多時.(不信的話可以參照Python 定義只讀屬性的方案二試試).

Python提供的最佳方案是通過property的setter方法:

class Item(): def __init__(self, category, count, price): self.__cat = category # attribute self.count = count # property self.price = price # property @property def cat(self): return self.__cat @property def count(self): return self.__dict__[’count’] @count.setter def count(self, value): if value < 0: raise ValueError(’count can not be minus: %r’%(value)) self.__dict__[’count’] = value @property def price(self): return self.__dict__[’price’] @price.setter def price(self, value): if value < 0: raise ValueError(’price can not be minus: %r’%(value)) self.__dict__[’price’] = value

之前合法的語句現在仍然可以正常運行:

item = Item(’Bread’, 1, 10)item.price = 20item.count = 2print(item.price)

但下面的語句執行時便會報錯了:

item = Item(’Bread’, 1, -10)# oritem.price = -10

會報出同一個錯誤:

---------------------------------------------------------------------------ValueErrorTraceback (most recent call last)<ipython-input-93-4fcbd1284b2d> in <module>()----> 1 item.price = -10<ipython-input-91-7546240b5469> in price(self, value) 27 def price(self, value): 28 if value < 0:---> 29 raise ValueError(’price can not be minus: %r’%(value)) 30 self.__dict__[’price’] = valueValueError: price can not be minus: -10

定義property的其他方式

@property中的property雖可被當作修飾器來使用, 但它其實是一個class(具體API請參考文檔), 所以上面的代碼還可以改寫為:

class Item(): def __init__(self, category, count, price): self.__cat = category # attribute self.count = count # property self.price = price # property def get_cat(self): return self.__cat def get_count(self): return self.__dict__[’count’] def set_count(self, value): if value < 0: raise ValueError(’count can not be minus: %r’%(value)) self.__dict__[’count’] = value def get_price(self): return self.__dict__[’price’] def set_price(self, value): if value < 0: raise ValueError(’price can not be minus: %r’%(value)) self.__dict__[’price’] = value bill = property(get_bill) cat = property(get_cat) count = property(get_count, set_count) price = property(get_price, set_price)

功能上達到要求了, 可代碼本身看起來很冗長, 比Java中的getter/setter風格還要長. 這時可以通過property factory來簡化代碼:

先定義可共用的property factory函數:

def readonly_prop(storage_name): def getter(instance): return instance.__dict__[storage_name] return property(getter)def positive_mutable_prop(storage_name): def getter(instance): return instance.__dict__[storage_name] def setter(instance, value): if value < 0: raise ValueError(’%s can not be minus: %r’%(storage_name, value)) instance.__dict__[storage_name] = value return property(getter, setter)

然后, 之前的示例代碼可以簡化為:

class Item(): def __init__(self, category, count, price): self.__cat = category # attribute self.count = count # property self.price = price # property cat = readonly_prop(’__cat’) count = positive_mutable_prop(’count’) price = positive_mutable_prop(’price’)

這樣一來, 在保證代碼簡潔的前提下實現了訪問控制和合法性驗證.

property不會被instance attribute覆蓋

之前在Python對象的屬性訪問過程一文中展示了attribute的解析過程, 從中知道class attribute可以被instance attribute覆蓋:

class Foo(): name = ’Foo’foo = Foo()foo.name = ’foo’codes = [’Foo.name’, ’foo.name’]for code in codes: print(code, ’=’, eval(code))

輸出為:

Foo.name = Foofoo.name = foo

但在property身上不會發生這種事情:

class Foo(): @property def name(self): return ’Foo’foo = Foo()foo.__dict__[’name’] = ’foo’# 已經不能通過foo.name賦值了codes = [’Foo.name’, ’foo.name’]for code in codes: print(code, ’=’, eval(code))

輸出:

Foo.name = <property object at 0x7fd135e7ecc8>foo.name = Foo

至少可以看出兩點:

1. 通過class Foo訪問Foo.name得到的是property對象, 而非property值.

2. 訪問 foo.name時返回的是Foo.name的property值. 究其原因, 是因為在屬性解析過程中, property的優先級是最高的.

總結

1.Python的attribute與property不同:

attribute: data attribute + method

property: replace attribute with access control methods like getter/setter, for security reasons.

2.可以通過多種方式定義property:

@property

property(getter, setter)

property factory

3.property在屬性解析時的優先級最高, 不會被instance attribute覆蓋.

以上這篇Python 從attribute到property詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: Python 編程
相關文章:
主站蜘蛛池模板: 青岛美佳乐清洁工程有限公司|青岛油烟管道清洗|酒店|企事业单位|学校工厂厨房|青岛油烟管道清洗 插针变压器-家用电器变压器-工业空调变压器-CD型电抗器-余姚市中驰电器有限公司 | 云杂志网-学术期刊-首页 | 广东西屋电气有限公司-广东西屋电气有限公司 | 淄博不锈钢无缝管,淄博不锈钢管-鑫门物资有限公司 | 污水提升器,污水提升泵,地下室排水,增压泵,雨水泵,智能供排水控制器-上海智流泵业有限公司 | 稳尚教育加盟-打造高考志愿填报平台_新高考志愿填报加盟_学业生涯规划加盟 | 龙门加工中心-数控龙门加工中心厂家价格-山东海特数控机床有限公司_龙门加工中心-数控龙门加工中心厂家价格-山东海特数控机床有限公司 | 西安展台设计搭建_西安活动策划公司_西安会议会场布置_西安展厅设计西安旭阳展览展示 | 信阳市建筑勘察设计研究院有限公司 | 钢骨架轻型板_膨石轻型板_钢骨架轻型板价格_恒道新材料 | 北京森语科技有限公司-模型制作专家-展览展示-沙盘模型设计制作-多媒体模型软硬件开发-三维地理信息交互沙盘 | 有机肥设备生产制造厂家,BB掺混肥搅拌机、复合肥设备生产线,有机肥料全部加工设备多少钱,对辊挤压造粒机,有机肥造粒设备 -- 郑州程翔重工机械有限公司 | 深圳激光打标机_激光打标机_激光焊接机_激光切割机_同体激光打标机-深圳市创想激光科技有限公司 深圳快餐店设计-餐饮设计公司-餐饮空间品牌全案设计-深圳市勤蜂装饰工程 | 无纺布包装机|径向缠绕包装机|缠绕膜打包机-上海晏陵智能设备有限公司 | 圣才学习网-考研考证学习平台,提供万种考研考证电子书、题库、视频课程等考试资料 | 电子厂招聘_工厂招聘_普工招聘_小时工招聘信息平台-众立方招工网 | 艺术生文化课培训|艺术生文化课辅导冲刺-济南启迪学校 | 机器视觉检测系统-视觉检测系统-机器视觉系统-ccd检测系统-视觉控制器-视控一体机 -海克易邦 | 阴离子_阳离子聚丙烯酰胺厂家_聚合氯化铝价格_水处理絮凝剂_巩义市江源净水材料有限公司 | 北京律师事务所_房屋拆迁律师_24小时免费法律咨询_云合专业律师网 | 无锡网站建设_企业网站定制-网站制作公司-阿凡达网络 | 滁州高低温冲击试验箱厂家_安徽高低温试验箱价格|安徽希尔伯特 | 517瓜水果特产网|一个专注特产好物的网站 | 轻型地埋电缆故障测试仪,频响法绕组变形测试仪,静荷式卧式拉力试验机-扬州苏电 | 新能源汽车教学设备厂家报价[汽车教学设备运营18年]-恒信教具 | 山东PE给水管厂家,山东双壁波纹管,山东钢带增强波纹管,山东PE穿线管,山东PE农田灌溉管,山东MPP电力保护套管-山东德诺塑业有限公司 | 垃圾压缩设备_垃圾处理设备_智能移动式垃圾压缩设备--山东明莱环保设备有限公司 | 中视电广_短视频拍摄_短视频推广_短视频代运营_宣传片拍摄_影视广告制作_中视电广 | 双齿辊破碎机-大型狼牙破碎机视频-对辊破碎机价格/型号图片-金联机械设备生产厂家 | 东莞办公家具厂家直销-美鑫【免费3D效果图】全国办公桌/会议桌定制 | 不锈钢水箱厂家,不锈钢保温水箱-山东桑特供水设备 | 安徽合肥格力空调专卖店_格力中央空调_格力空调总经销公司代理-皖格制冷设备 | 自进式锚杆-自钻式中空注浆锚杆-洛阳恒诺锚固锚杆生产厂家 | 玻纤土工格栅_钢塑格栅_PP焊接_单双向塑料土工格栅_复合防裂布厂家_山东大庚工程材料科技有限公司 | 国标白水泥,高标号白水泥,白水泥厂家-淄博华雪建材有限公司 | 智慧农业|农业物联网|现代农业物联网-托普云农物联网官方网站 | 哈希PC1R1A,哈希CA9300,哈希SC4500-上海鑫嵩实业有限公司 | 澳门精准正版免费大全,2025新澳门全年免费,新澳天天开奖免费资料大全最新,新澳2025今晚开奖资料,新澳马今天最快最新图库 | 防弹玻璃厂家_防爆炸玻璃_电磁屏蔽玻璃-四川大硅特玻科技有限公司 | 体坛网_体坛+_体坛周报新闻客户端 | 苏州教学设备-化工教学设备-环境工程教学模型|同科教仪 |