真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Python中從attribute到property的示例分析-創(chuàng)新互聯(lián)

這篇文章主要為大家展示了“Python中從attribute到property的示例分析”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Python中從attribute到property的示例分析”這篇文章吧。

創(chuàng)新互聯(lián)建站IDC提供業(yè)務(wù):德陽(yáng)電信服務(wù)器托管,成都服務(wù)器租用,德陽(yáng)電信服務(wù)器托管,重慶服務(wù)器租用等四川省內(nèi)主機(jī)托管與主機(jī)租用業(yè)務(wù);數(shù)據(jù)中心含:雙線機(jī)房,BGP機(jī)房,電信機(jī)房,移動(dòng)機(jī)房,聯(lián)通機(jī)房。

字面意思上的區(qū)別

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

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.

簡(jiǎn)單來(lái)說(shuō), property是類(lèi)的本質(zhì)屬性, 可用于定義和描述一個(gè)類(lèi)別或物種; attribute則是用于詳細(xì)說(shuō)明它所描述的物體, 是物體的具體屬性.

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

從這個(gè)意義上講, property是attribute的子集.

Python里的attribute與property

回到Python.

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

Python中從attribute到property的示例分析

接下來(lái)分別解釋.

attribute

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

例如:

# Python3
class Foo():
 name = 'Foo class attribute'
 def fn(self):
  pass
print('class attribute:', Foo.__dict__)
print()
foo = Foo()
foo.name = 'foo instance attribute'
print('instance attribute:', foo.__dict__)

輸出:

class attribute: {'fn': , ... , 'name': 'Foo class attribute'}

instance attribute: {'name': 'foo instance attribute'}

property

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

只讀屬性

例如:

class Foo():
 def __init__(self, name):
  self.name = name

foo = 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 changed
foo.name = Unluckily, I can be changed

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

將上面的foo.name改寫(xiě)成property:

class Foo():
 def __init__(self, name):
  self.__name = name

 @property
 def name(self):
  return self.__name

foo = 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)
 in ()
  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

有兩點(diǎn)需要注意:

foo.name確實(shí)已經(jīng)不能通過(guò)foo.name = ...來(lái)修改了, 即, foo.name已經(jīng)是只讀屬性.

將foo.name從attribute變成property之后, 它的訪問(wèn)方式并沒(méi)有改變. 也就是說(shuō), 對(duì)外接口沒(méi)有改變. 這個(gè)優(yōu)點(diǎn)可以讓我們從容的寫(xiě)代碼, 不用在一開(kāi)始就糾結(jié)于是使用property還是attribute, 因?yàn)榭梢远际褂胊ttribute, 如果有需要, 以后可以在不影響外部代碼的前提下隨時(shí)修改. 而在Java里要做到這一點(diǎn)很難(如果可以做到的話).

屬性值合法性驗(yàn)證

在上面的例子中, foo.name只有g(shù)etter方法, 是只讀的, 但其實(shí)property也是可修改的, 只需要為它添加一個(gè)setter方法就行了. 那么問(wèn)題就來(lái)了, 如果property也是可讀可改, 那為何要費(fèi)事將attribute改寫(xiě)成property呢?

想象一個(gè)簡(jiǎn)單的購(gòu)物相關(guān)的業(yè)務(wù)場(chǎng)景. 一個(gè)Item代表用戶(hù)購(gòu)買(mǎi)的一樣?xùn)|西, 主要有類(lèi)別, 價(jià)格和數(shù)量屬性:

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

正常的調(diào)用是類(lèi)似于這樣的, 價(jià)格與數(shù)量都是正數(shù):

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

可是, 若價(jià)格或數(shù)量設(shè)置為負(fù)數(shù)也不會(huì)報(bào)錯(cuò):

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

從語(yǔ)法上看, 這些語(yǔ)句都是合法的, 但從業(yè)務(wù)上看, 它們都是不合法的. 那么, 怎樣才能防止這種非法賦值呢? 一種解決方案是按照J(rèn)ava風(fēng)格, 實(shí)現(xiàn)一個(gè)Java式的setter方法, 通過(guò)item.set_price(price)設(shè)置price屬性, 然后在set_price方法里寫(xiě)驗(yàn)證代碼. 這樣是可行的, 但不夠Pythonic. Python的風(fēng)格是讀與寫(xiě)都通過(guò)屬性名進(jìn)行:

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

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

Python提供的最佳方案是通過(guò)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

之前合法的語(yǔ)句現(xiàn)在仍然可以正常運(yùn)行:

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

但下面的語(yǔ)句執(zhí)行時(shí)便會(huì)報(bào)錯(cuò)了:

item = Item('Bread', 1, -10)
# or
item.price = -10

會(huì)報(bào)出同一個(gè)錯(cuò)誤:

---------------------------------------------------------------------------
ValueError        Traceback (most recent call last)
 in ()
----> 1 item.price = -10

 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'] = value

ValueError: price can not be minus: -10

定義property的其他方式

@property中的property雖可被當(dāng)作修飾器來(lái)使用, 但它其實(shí)是一個(gè)class(具體API請(qǐng)參考文檔), 所以上面的代碼還可以改寫(xiě)為:

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)

功能上達(dá)到要求了, 可代碼本身看起來(lái)很冗長(zhǎng), 比Java中的getter/setter風(fēng)格還要長(zhǎng). 這時(shí)可以通過(guò)property factory來(lái)簡(jiǎn)化代碼:

先定義可共用的property factory函數(shù):

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)

然后, 之前的示例代碼可以簡(jiǎn)化為:

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')

這樣一來(lái), 在保證代碼簡(jiǎn)潔的前提下實(shí)現(xiàn)了訪問(wèn)控制和合法性驗(yàn)證.

property不會(huì)被instance attribute覆蓋

之前在Python對(duì)象的屬性訪問(wèn)過(guò)程一文中展示了attribute的解析過(guò)程, 從中知道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 = Foo
foo.name = foo

但在property身上不會(huì)發(fā)生這種事情:

class Foo():
 @property
 def name(self):
  return 'Foo'

foo = Foo()
foo.__dict__['name'] = 'foo'# 已經(jīng)不能通過(guò)foo.name賦值了
codes = ['Foo.name', 'foo.name']
for code in codes:
 print(code, '=', eval(code))

輸出:

Foo.name =
foo.name = Foo

至少可以看出兩點(diǎn):

1. 通過(guò)class Foo訪問(wèn)Foo.name得到的是property對(duì)象, 而非property值.

2. 訪問(wèn) foo.name時(shí)返回的是Foo.name的property值. 究其原因, 是因?yàn)樵趯傩越馕鲞^(guò)程中, property的優(yōu)先級(jí)是最高的.

總結(jié)

1.Python的attribute與property不同:

attribute: data attribute + method

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

2.可以通過(guò)多種方式定義property:

@property

property(getter, setter)

property factory

3.property在屬性解析時(shí)的優(yōu)先級(jí)最高, 不會(huì)被instance attribute覆蓋.

以上是“Python中從attribute到property的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


本文標(biāo)題:Python中從attribute到property的示例分析-創(chuàng)新互聯(lián)
標(biāo)題來(lái)源:http://weahome.cn/article/dpiojh.html

其他資訊

在線咨詢(xún)

微信咨詢(xún)

電話咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部