成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Python中的動(dòng)態(tài)屬性和特性

scola666 / 3070人閱讀

摘要:一利用動(dòng)態(tài)屬性處理數(shù)據(jù)源屬性在中,數(shù)據(jù)的屬性和處理數(shù)據(jù)的方法統(tǒng)稱(chēng)屬性。處理無(wú)效屬性名在中,由于關(guān)鍵字被保留,名稱(chēng)為關(guān)鍵字的屬性是無(wú)效的。內(nèi)置函數(shù)列出對(duì)象的大多數(shù)屬性。點(diǎn)號(hào)和內(nèi)置函數(shù)會(huì)觸發(fā)這個(gè)方法。

導(dǎo)語(yǔ):本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之元編程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門(mén)Python的朋友們可以來(lái)一起學(xué)習(xí)并交流。

本文重點(diǎn):

1、了解如何利用動(dòng)態(tài)屬性處理數(shù)據(jù);
2、掌握Python中的特性概念以及@property裝飾器;
3、了解Python中處理屬性的重要屬性和函數(shù)。
一、利用動(dòng)態(tài)屬性處理JSON數(shù)據(jù)源

屬性:在Python中,數(shù)據(jù)的屬性和處理數(shù)據(jù)的方法統(tǒng)稱(chēng)屬性。
元編程:用元類(lèi)進(jìn)行編程,元類(lèi)→類(lèi)→對(duì)象,元類(lèi)比類(lèi)更抽象,生成類(lèi)的類(lèi)。

1、使用動(dòng)態(tài)屬性訪問(wèn)JSON類(lèi)數(shù)據(jù)

第一版:利用json.load(fp)審查數(shù)據(jù)

from urllib.request import urlopen
import warnings
import os
import json

URL = "http://www.oreilly.com/pub/sc/osconfeed"
JSON = "data/osconfeed.json"

def load():
    if not os.path.exists(JSON):
        msg = "downloading {} to {}".format(URL, JSON)
        warnings.warn(msg) #如果需要下載就發(fā)出提醒。
        with urlopen(URL) as remote, open(JSON, "wb") as local: #在with語(yǔ)句中使用兩個(gè)上下文管理器分別用于讀取和保存遠(yuǎn)程文件。
            local.write(remote.read())
    with open(JSON) as fp:
        return json.load(fp)#json.load函數(shù)解析JSON文件,返回Python原生對(duì)象。

第二版:使用動(dòng)態(tài)屬性訪問(wèn)JSON類(lèi)數(shù)據(jù)
第一版查閱深層數(shù)據(jù)的格式比較冗長(zhǎng),例如feed"Schedule"40,我們希望在讀取屬性上采用feed.Schedule.events[40].name這類(lèi)方式來(lái)改進(jìn)。并且第二版的類(lèi)能遞歸,自動(dòng)處理嵌套的映射和列表。

from collections import abc

class FronenJSON:
    def __init__(self,mapping):
        self.__data=dict(mapping)#創(chuàng)建副本,同時(shí)確保處理的是字典。
        
    def __getattr__(self, name):#僅當(dāng)沒(méi)有指定名稱(chēng)的屬性才調(diào)用__getattr__方法。
        if hasattr(self,name):
            return getattr(self.__data,name)
        else:
            return FronenJSON.build(self.__data[name])
   
    @classmethod    
    def __build__(cls,obj):
        if isinstance(obj,abc.Mapping):#判斷obj是否是映射。
            return cls(obj)#創(chuàng)建FrozenJSON對(duì)象。
        elif isinstance(obj,abc.MutableSequence):
            return [cls.build(item) for item in obj]#遞歸調(diào)用.build()方法,構(gòu)建一個(gè)列表。
        else:#既不是字典也不是列表,則返回元素本身。
            return obj

分析: FronenJSON類(lèi)的關(guān)鍵是__getattr__方法。僅當(dāng)無(wú)法使用常規(guī)的方式獲取屬性(即在實(shí)例、類(lèi)或超類(lèi)中找不到指定的屬性),解釋器才會(huì)調(diào)用特殊的__getattr__方法。

2、處理無(wú)效屬性名

在Python中,由于關(guān)鍵字被保留,名稱(chēng)為關(guān)鍵字的屬性是無(wú)效的。因此需要對(duì)第二版中的__init__進(jìn)行改進(jìn):

    def __init__(self,mapping):
        self.__data={}
        for key,value in mapping.items():
            if keyword.iskeyword(key):
                key+="_"#與Python關(guān)鍵字重復(fù)的key在尾部加上下劃線。
            self.__data[key]=value
3、使用特殊方法__new__

第三版:使用__new__構(gòu)造方法把一個(gè)類(lèi)轉(zhuǎn)換成一個(gè)靈活的對(duì)象工廠函數(shù)。

from collections import abc

class FronenJSON:
    def __new__(cls, arg):  # __new__是類(lèi)方法,第一個(gè)參數(shù)是類(lèi)本身cls。
        if isinstance(arg, abc.Mapping):
            return super().__new__(cls)  #委托給超類(lèi)object基類(lèi)的__new__方法處理。
        elif isinstance(arg, abc.MutableSequence):  # 余下方法與原先的build方法一致。
            return [cls(item) for item in arg]
        else:
            return arg
 
     def __init__(self,mapping):
        self.__data={}
        for key,value in mapping.items():
            if keyword.iskeyword(key):
                key+="_"
            self.__data[key]=value 

    def __getattr__(self, name):
        if hasattr(self,name):
            return getattr(self.__data,name)
        else:
            return FronenJSON(self.__data[name])  
二、特性 1、類(lèi)屬性、實(shí)例屬性、私有屬性與特性

類(lèi)屬性:類(lèi)屬性在__init__()外初始化,屬于類(lèi)所有,所有實(shí)例共享一個(gè)屬性。
調(diào)用方法:類(lèi)屬性在內(nèi)部用classname.類(lèi)屬性名調(diào)用,外部既可以用classname.類(lèi)屬性名又可以用instancename.類(lèi)屬性名來(lái)調(diào)用。

實(shí)例屬性:實(shí)例屬性屬于各個(gè)實(shí)例所有,互不干擾。

私有屬性

單下劃線_開(kāi)頭:只是告訴別人這是私有屬性,外部依然可以訪問(wèn)更改。

雙下劃線__開(kāi)頭:外部不可通過(guò)instancename.propertyname來(lái)訪問(wèn)或者更改,實(shí)際將其轉(zhuǎn)化為了_classname__propertyname。

特性:是用于管理實(shí)例屬性的類(lèi)屬性。
特性用途:經(jīng)常用于把公開(kāi)的屬性變成使用讀值方法和設(shè)值方法管理的屬性,且在不影響客戶(hù)端代碼的前提下實(shí)施業(yè)務(wù)規(guī)則。

注意

不要對(duì)實(shí)例屬性和類(lèi)屬性使用相同的名字。否則實(shí)例屬性會(huì)遮蓋類(lèi)屬性,發(fā)生難以發(fā)現(xiàn)的錯(cuò)誤。

實(shí)例屬性不會(huì)遮蓋類(lèi)特性,但類(lèi)特性會(huì)遮蓋實(shí)例屬性。
這是因?yàn)閛bj.attr不會(huì)從實(shí)例obj開(kāi)始尋找attr,而是從obj.__class__開(kāi)始;而且僅當(dāng)類(lèi)中沒(méi)有名為attr的特性時(shí),Python才會(huì)在實(shí)例中尋找attr。

簡(jiǎn)言之,就遮蓋層級(jí)而言,類(lèi)特性>實(shí)例屬性>類(lèi)屬性。

2、使用特性驗(yàn)證屬性

使用特性可以驗(yàn)證實(shí)例屬性的有效性,同時(shí)能夠根據(jù)已知屬性和屬性之間的關(guān)系式調(diào)整其他屬性,避免硬編碼。
案例:假設(shè)某商店經(jīng)營(yíng)堅(jiān)果、雜糧等多種有機(jī)食物,每位顧客的訂單會(huì)包含店中的一系列商品,我們需要根據(jù)客戶(hù)的訂單計(jì)算出總價(jià)。
分析:我們不希望顧客訂單的商品重量為非正數(shù),需要借助@property裝飾器實(shí)現(xiàn)值的獲取與設(shè)置,從而驗(yàn)證實(shí)例屬性的有效性。代碼如下:

class LineItem:
    def __init__(self,description,weight,price):
        self.description=description
        self.weight=weight
        self.price=price

    def subtotal(self):
        return self.weight*self.price

    @property#讀值。
    def weight(self):
        return self.__weight#真正的值存儲(chǔ)在私有屬性中。

    @weight.setter
    def weight(self,value):
        if value >0:
            self.__weight=value#有效值存入私有屬性中。
        else:
            raise ValueError("Value must be > 0")#對(duì)于無(wú)效的值拋出ValueError。

Tips:當(dāng)我們需要設(shè)置只讀屬性時(shí),只使用@property,無(wú)需使用@func.setter。

原理解析:為了更好地理解@property裝飾器的原理,我們寫(xiě)一版效果相同但沒(méi)使用裝飾器的代碼。

class LineItem:
    def __init__(self, description, weight, price):
        self.description = description
        self.weight = weight
        self.price = price

    def subtotal(self):
        return self.weight * self.price

    def get_weight(self): #普通讀值方法。
        return self.__weight

    def set_weight(self, value): #普通設(shè)值方法。
        if value > 0:
            self.__weight = value
        else:
            raise ValueError("value must be > 0")
    weight = property(get_weight, set_weight) #構(gòu)建property對(duì)象,賦值給公開(kāi)的類(lèi)特性。

property 構(gòu)造方法的完整簽名:

property(fget=None, fset=None, fdel=None, doc=None)
3、特性工廠函數(shù)

抽象定義特性的方式有兩種,一是使用特性工廠函數(shù),二是使用描述符類(lèi)。
下面我們用特性工廠函數(shù)來(lái)完成上文中提到的訂單結(jié)算案例:

def quantity(storage_name):  

    def qty_getter(instance):  # instance指的是要把屬性存儲(chǔ)其中的LineItem實(shí)例。
        return instance.__dict__[storage_name]  # 引用閉包中的自由變量storage_name,值直接從instance.__dict__中獲取,以便跳過(guò)特性,防止無(wú)限遞歸。

    def qty_setter(instance, value):  
        if value > 0:
            instance.__dict__[storage_name] = value  # 同理存儲(chǔ),跳過(guò)特性。
        else:
            raise ValueError("value must be > 0")

    return property(qty_getter, qty_setter)  # 構(gòu)建自定義特性對(duì)象并返回。

class LineItem:
    weight = quantity("weight")  # 將自定義特性weight定義為類(lèi)屬性。
    price = quantity("price")  # 同上。

    def __init__(self, description, weight, price):
        self.description = description
        self.weight = weight  # 此處特性已經(jīng)激活,可驗(yàn)證值的有效性。
        self.price = price

    def subtotal(self):
        return self.weight * self.price  # 此處利用特性獲取實(shí)例中存儲(chǔ)的值。
4、使用特性刪除屬性
class BlackKnight:
  def __init__(self):
      self.members = ["an arm", "another arm",
                      "a leg", "another leg"]
      self.phrases = [""Tis but a scratch.",
                      "It"s just a flesh wound.",
                      "I"m invincible!",
                      "All right, we"ll call it a draw."]

  @property
  def member(self):
      print("next member is:")
      return self.members[0]

  @member.deleter
  def member(self):
      text = "BLACK KNIGHT (loses {})
-- {}"
      print(text.format(self.members.pop(0), self.phrases.pop(0)))

刪除屬性只需在主程序中發(fā)出指令:del obj.attr

三、處理屬性的重要屬性和函數(shù) 1、特殊屬性

__class__:對(duì)象所屬類(lèi)的引用(即obj.__class__和type(obj)的作用相同)。Python中的某些特殊方法比如 __getattr__,只在對(duì)象的類(lèi)中尋找,而不在實(shí)例中尋找。

__dict__:一個(gè)映射,存儲(chǔ)對(duì)象或類(lèi)的可寫(xiě)屬性。

__slots__:類(lèi)可以定義這個(gè)屬性,限制實(shí)例有哪些屬性。

2、內(nèi)置函數(shù)

dir([object]):列出對(duì)象的大多數(shù)屬性。

getattr(object,name[,default]):從object對(duì)象中獲取name字符串對(duì)應(yīng)的屬性。獲取的屬性可能來(lái)自對(duì)象所屬的類(lèi)或超類(lèi)。

hasattr(object,name):若object對(duì)象中存在指定的屬性,或者能以某種方式(如繼承)通過(guò)object對(duì)象獲取指定的屬性,返回True。

setattr(object,name,value):把object對(duì)象指定屬性的值設(shè)為value,前提是object對(duì)象能接受那個(gè)值。這個(gè)函數(shù)可能會(huì)創(chuàng)建一個(gè)新屬性,或者覆蓋現(xiàn)有的屬性。

var([object]):返回object對(duì)象的__dict__屬性。

3、特殊方法

__delattr__(self,name):只要使用del語(yǔ)句刪除屬性,就會(huì)調(diào)用這個(gè)方法。

__dir__(self):把對(duì)象傳給dir函數(shù)時(shí)調(diào)用,列出屬性。

__getattr__(self,name):僅當(dāng)獲取指定的屬性失敗,搜索過(guò)obj,Class和超類(lèi)之后調(diào)用。

__getattribute__(self,name):嘗試獲取指定的屬性時(shí)總會(huì)調(diào)用這個(gè)方法。不過(guò)尋找的屬性是特殊屬性或特殊方法時(shí)除外。為了防止無(wú)限遞歸,__getattribute__方法的實(shí)現(xiàn)要使用super().__getattribute__(obj,name)。

__setattr__(self,name,value):嘗試設(shè)置指定的屬性時(shí)總會(huì)調(diào)用這個(gè)方法。點(diǎn)號(hào)和setattr內(nèi)置函數(shù)會(huì)觸發(fā)這個(gè)方法。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41455.html

相關(guān)文章

  • Python中的屬性描述符

    摘要:下面我們用描述符來(lái)實(shí)現(xiàn)中的動(dòng)態(tài)屬性和特性中提及的訂單結(jié)算代碼第四版使用描述符實(shí)現(xiàn)訂單結(jié)算功能描述符基于協(xié)議實(shí)現(xiàn),無(wú)需創(chuàng)建子類(lèi)。特性是覆蓋型描述符。非覆蓋型描述符沒(méi)有實(shí)現(xiàn)方法的描述符屬于非覆蓋型描述符。類(lèi)中定義的方法是非覆蓋型描述符。 導(dǎo)語(yǔ):本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之元編程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門(mén)Python的朋友們可以來(lái)一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、了解描述符...

    geekzhou 評(píng)論0 收藏0
  • Python動(dòng)態(tài)特性應(yīng)對(duì)動(dòng)態(tài)情況

    摘要:有一些定制類(lèi)的特殊方法,如,其中一些具有動(dòng)態(tài)特性的方法可以用來(lái)很方便地處理某些動(dòng)態(tài)狀況。動(dòng)態(tài)化屬性和方法的調(diào)用,當(dāng)調(diào)用不存在的屬性時(shí),如果存在方法,就會(huì)調(diào)用方法來(lái)嘗試獲得屬性。這種完全動(dòng)態(tài)的調(diào)用可以應(yīng)對(duì)一些動(dòng)態(tài)情況,例如實(shí)現(xiàn)。 Python有一些定制類(lèi)的特殊方法,如__str__()、__iter__()、__getitem__(),其中一些具有動(dòng)態(tài)特性的方法可以用來(lái)很方便地處理某些動(dòng)...

    Vicky 評(píng)論0 收藏0
  • python3 學(xué)習(xí)筆記

    摘要:本人很少寫(xiě)代碼一般都是用的去年時(shí)用寫(xiě)過(guò)一些收集系統(tǒng)信息的工具當(dāng)時(shí)是邊看手冊(cè)邊寫(xiě)的如今又要用來(lái)寫(xiě)一個(gè)生成的工具就又需要查看手冊(cè)了至于為什么不用寫(xiě)那是因?yàn)榈膸?kù)不兼容永中在這里不得不說(shuō)雖然很火但是一些庫(kù)還是不如多不如兼容性好為了避免以后再出這種事 Python3 Study Notes 本人很少寫(xiě) python 代碼, 一般都是用 go 的, 去年時(shí)用 python 寫(xiě)過(guò)一些收集系統(tǒng)信息的工...

    tuomao 評(píng)論0 收藏0
  • Python 面試」第二次更新

    摘要:結(jié)果為對(duì)于迭代器和生成器你知道哪些,它們分別應(yīng)用于什么場(chǎng)景先介紹什么是可迭代的任何可用于循環(huán)的都是可迭代的。示例結(jié)果為,迭代器任何可以使用函數(shù)的都是迭代器,也可使用函數(shù)將可迭代對(duì)象變?yōu)榈鳌N磳?xiě)完,下次更新補(bǔ)上。 showImg(https://segmentfault.com/img/bVbuN3P); 閱讀本文大約需要 8 分鐘。 7.說(shuō)一下 Python 中的裝飾器 原理:利用...

    Yu_Huang 評(píng)論0 收藏0
  • Python學(xué)習(xí)之路30-接口:從協(xié)議到抽象基類(lèi)

    摘要:本篇內(nèi)容將從鴨子類(lèi)型的動(dòng)態(tài)協(xié)議,逐漸過(guò)渡到使接口更明確能驗(yàn)證實(shí)現(xiàn)是否符合規(guī)定的抽象基類(lèi)。抽象基類(lèi)介紹完動(dòng)態(tài)實(shí)現(xiàn)接口后,現(xiàn)在開(kāi)始討論抽象基類(lèi),它屬于靜態(tài)顯示地實(shí)現(xiàn)接口。標(biāo)準(zhǔn)庫(kù)中的抽象基類(lèi)從開(kāi)始,標(biāo)準(zhǔn)庫(kù)提供了抽象基類(lèi)。 《流暢的Python》筆記。本篇是面向?qū)ο髴T用方法的第四篇,主要討論接口。本篇內(nèi)容將從鴨子類(lèi)型的動(dòng)態(tài)協(xié)議,逐漸過(guò)渡到使接口更明確、能驗(yàn)證實(shí)現(xiàn)是否符合規(guī)定的抽象基類(lèi)(Abst...

    LucasTwilight 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<