国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Python中的序列修改、散列和切片

jubincn / 2034人閱讀

摘要:一基本的序列協(xié)議首先,需要就維向量和二維向量的顯示模的計算等差異重新調(diào)整。假設(shè)維向量最多能處理維向量,訪問向量分量的代碼實現(xiàn)如下若傳入的參數(shù)在備選分量中可進(jìn)行后續(xù)處理判斷分量的位置索引是否超出實例的邊界不支持非法的分量訪問,拋出。

導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之面向?qū)ο笃闹攸c知識及個人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。

本文重點:

1、了解協(xié)議的概念以及利用__getitem__和__len__實現(xiàn)序列協(xié)議的方法;
2、掌握切片背后的__getitem__;
3、掌握動態(tài)訪問屬性背后的__getattr__和__setattr__;
4、掌握實現(xiàn)可散列對象背后精簡的__hash__和__eq__。

注:本文介紹的vector類將二維vector類推廣到多維,跟不上本文的朋友可以移步至《編寫符合Python風(fēng)格的對象》先了解二維向量類的編寫。

一、基本的序列協(xié)議

首先,需要就n維向量和二維向量的顯示、模的計算等差異重新調(diào)整。n維向量的設(shè)計包括初始化,迭代,輸出,向量實例轉(zhuǎn)為字節(jié)序列,求模,求布爾值,比較等內(nèi)容,代碼如下:

import math
import reprlib
from array import array

class Vector:
    typecode="d"
    def __init__(self,components):
        self._components=array(self.typecode,components)

    def __str__(self):
        return str(tuple(self))

    def __iter__(self):
        return iter(self._components)

    def __repr__(self):
        classname=type(self).__name__
        components=reprlib.repr(self._components)
        components=components[components.find("["):-1]
        return "{}({})".format(classname,components)

    def __eq__(self, other):
        return tuple(self)==tuple(other)

    def __abs__(self):
        return math.sqrt(sum(x*x for x in self))

    def __bytes__(self):
        return (bytes(self.typecode,encoding="utf-8")+
                bytes(array(self.typecode,self._components)))

    def __bool__(self):
        return bool(abs(self)

    @classmethod
    def frombytes(cls,seqs):
        typecode=chr(seqs[0])
        memv=memoryview(seqs[1:]).cast(typecode)
        return cls(memv)

在Python中創(chuàng)建功能完善的序列類型無需使用繼承,只需要實現(xiàn)符合序列協(xié)議的__len__和__getitem__,具體代碼實現(xiàn)如下:

class Vector:
    #省略中間代碼
    def __len__(self):
        return len(self._components)
    
    def __getitem__(self, item):
        return self._components[item]

在面向?qū)ο缶幊讨校瑓f(xié)議是非正式的接口,沒有強制力。因此如果知道類的具體使用場景,實現(xiàn)協(xié)議中的一部分也可以。例如,為了支持迭代只實現(xiàn)__getitem__方法即可。

二、切片原理 1、了解切片的行為

在對序列切片(slice)的操作中,解釋器允許切片省略start,stop,stride中的部分值甚至是全部省略。通過dir(slice)查閱發(fā)現(xiàn),是切片背后的indices在做這個工作。indices方法會整頓存儲數(shù)據(jù)屬性的元組,把start,stop,stride都變成非負(fù)數(shù),而且都落在指定長度序列的邊界內(nèi)。
例如slice(-3,None,None).indices(5)整頓完畢之后是(2,5,1)這樣合理的切片。

2、關(guān)鍵的__getitem__方法

__getitem__是支持迭代取值的特殊方法。我們將上文的__getitem__改造成可以處理切片的方法,改造需要考慮到處理參數(shù)是否為合理切片,合理切片的操作結(jié)果是產(chǎn)生新的向量實例。

    def __getitem__(self, index):
        cls=type(self)
        if isinstance(index,slice):
            return cls(self._components[index])#判斷參數(shù)為切片時返回新的向量實例
        elif isinstance(index,numbers.Integral):
            return self._components[index]#判斷參數(shù)為數(shù)值時返回對應(yīng)的數(shù)值
        else:
            msg="{cls.__name__} indices must be integers"
            raise TypeError(msg.format(cls=cls))#判斷參數(shù)不合理時拋出TypeError
三、動態(tài)存取屬性 1、訪問向量分量:__getattr__

n維向量沒有像二維向量一樣把訪問分量的方式直接在__init__中寫入,由于傳入的維數(shù)不確定無法采取窮舉分量的原始方法,為此我們需要借助__getattr__實現(xiàn)。假設(shè)n維向量最多能處理6維向量,訪問向量分量的代碼實現(xiàn)如下:

    shortcut_names="xyztpq"
    def __getattr__(self, name):
        cls=type(self)
        if len(name)==1:
            index=cls.shortcut_names.find(str(name))#若傳入的參數(shù)在備選分量中可進(jìn)行后續(xù)處理
            if 0<=index

Tips:代碼嚴(yán)謹(jǐn)之處在于傳入的參數(shù)即使在備選分量之中,也有可能會超出實例的邊界,因此涉及到索引和邊界需要認(rèn)真注意這一點。

2、保持行為一致:__setattr__

盡管我們實現(xiàn)了__getattr__,但事實上目前的n維向量存在行為不一致的問題,先看一段代碼:

v=Vector(range(5))
print(v.y)#輸出1.0
v.y=6
print(v.y)#輸出6
print(v)#輸出(0.0, 1.0, 2.0, 3.0, 4.0)

上面的例子顯示我們可以訪問6維向量的y分量,但是問題在于我們?yōu)閥分量賦值的改動沒有影響到向量實例v。這種行為是不一致的,并且還沒有拋出錯誤令人匪夷所思。本文中我們希望向量分量是只讀不可變的,也就是說我們要對修改向量分量這種不當(dāng)?shù)男袨閽伋鯡rror。因此需要額外構(gòu)造__setattr__,代碼實現(xiàn)如下:

    def __setattr__(self, key, value):
        cls=type(self)
        if len(key)==1:
            if key in self.shortcut_names:
                error="can"t set value to attribute {attr_name!r}"
            elif key.islower():
                error="can"t set attributes "a" to "z" in {cls_name!r}"
            else:
                error=""
            if error:#寫嵌套語句的時候要始終把握住邏輯思路。
                msg = error.format(cls_name=cls.__name__, attr_name=key)
                raise AttributeError(msg)
        super().__setattr__(key,value)#在超類上調(diào)用__setattr__方法來提供標(biāo)準(zhǔn)行為。

小結(jié):如果定義了__getattr__方法,那么也要定義__setattr__方法,這樣才能避免行為不一致。

四、可散列的對象

可散列對象應(yīng)滿足的三個條件在此不再贅述,對于n維向量類而言需要做兩件事將其散列化:

1、利用異或運算符構(gòu)造__hash__

構(gòu)造思路是將hash()應(yīng)用到向量中的每個元素,并用異或運算符進(jìn)行聚合計算。由于處理的向量維數(shù)提高,采用歸約函數(shù)functools.reduce處理。

import operator
from functools import reduce
    def __hash__(self):
        hashes=map(hash,self._components)
        return reduce(operator.xor,hashes)
2、通過zip優(yōu)化n維向量的比較方法__eq__

上文初始給出的比較方法是粗糙的,下面針對兩個維數(shù)均不確定的向量進(jìn)行比較,代碼如下:

 def __eq__(self, other):
     if len(self)!=len(other):#數(shù)組數(shù)量的比較很關(guān)鍵
         return False
     for x,y in zip(self,other):
         if x!=y:
             return False
     return True

數(shù)組數(shù)量的比較時很關(guān)鍵的,因為zip在比較數(shù)量不等的序列時會隨著一個輸入的耗盡而停止迭代,并且不拋出Error。
回到正題,上述的邏輯關(guān)系可以進(jìn)一步精簡。通過all函數(shù)可以把for循環(huán)替代:

    def __eq__(self, other):
         return len(self)==len(other) and all(x==y for x,y in zip(self,other))

本人更喜歡后者這種簡潔且準(zhǔn)確的代碼書寫方式。

五、格式化顯示

理解n維向量的超球面坐標(biāo)(r,θ1,θ2,θ3,...,θn-1)計算公式需要額外的數(shù)學(xué)基礎(chǔ),此處的格式化輸出在本質(zhì)上與《編寫符合Python風(fēng)格的對象》中的格式化輸出并無明顯區(qū)別,此處不作詳述,感興趣的朋友可以查看如下的代碼:

    def angle(self, n): #使用公式計算角坐標(biāo)
        r = math.sqrt(sum(x * x for x in self[n:]))
        a = math.atan2(r, self[n-1])
        if (n == len(self) - 1) and (self[-1] < 0):
            return math.pi * 2 - a
        else:
            return a

    def angles(self): 
        return (self.angle(n) for n in range(1, len(self)))#計算所有角坐標(biāo)并存入生成器表達(dá)式中

    def __format__(self, fmt_spec=""):
        if fmt_spec.endswith("h"): # 超球面坐標(biāo)標(biāo)識符
             fmt_spec = fmt_spec[:-1]
            coords = itertools.chain([abs(self)],self.angles()) #利用itertools.chain無縫迭代模和角坐標(biāo)
            outer_fmt = "<{}>" 
        else:
            coords = self
            outer_fmt = "({})" 
        components = (format(c, fmt_spec) for c in coords) #格式化極坐標(biāo)的各元素并存入生成器中
        return outer_fmt.format(", ".join(components)) 

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/41277.html

相關(guān)文章

  • Python學(xué)習(xí)之路29-序列修改列和切片

    摘要:具體方法和上一篇一樣,也是用各個分量的哈希值進(jìn)行異或運算,由于的分量可能很多,這里我們使用函數(shù)來歸約異或值。每個分量被映射成了它們的哈希值,這些哈希值再歸約成一個值這里的傳入了第三個參數(shù),并且建議最好傳入第三個參數(shù)。 《流暢的Python》筆記。本篇是面向?qū)ο髴T用方法的第三篇。本篇將以上一篇中的Vector2d為基礎(chǔ),定義多維向量Vector。 1. 前言 自定義Vector類的行為...

    馬忠志 評論0 收藏0
  • 流暢的python讀書筆記-第十章-序列修改列和切片

    摘要:例如,的序列協(xié)議只需要和兩個方法。任何類如,只要使用標(biāo)準(zhǔn)的簽名和語義實現(xiàn)了這兩個方法,就能用在任何期待序列的地方。方法開放了內(nèi)置序列實現(xiàn)的棘手邏輯,用于優(yōu)雅地處理缺失索引和負(fù)數(shù)索引,以及長度超過目標(biāo)序列的切片。 序列的修改、散列和切片 接著造Vector2d類 要達(dá)到的要求 為了編寫Vector(3, 4) 和 Vector(3, 4, 5) 這樣的代碼,我們可以讓 init 法接受任...

    cpupro 評論0 收藏0
  • Python入門學(xué)習(xí)筆記匯總

    摘要:導(dǎo)語本文章匯總了本人在學(xué)習(xí)基礎(chǔ)之緒論篇數(shù)據(jù)結(jié)構(gòu)篇函數(shù)篇面向?qū)ο笃刂屏鞒唐驮幊唐獙W(xué)習(xí)筆記的鏈接,打算入門的朋友們可以按需查看并交流。 導(dǎo)語:本文章匯總了本人在學(xué)習(xí)Python基礎(chǔ)之緒論篇、數(shù)據(jù)結(jié)構(gòu)篇、函數(shù)篇、面向?qū)ο笃⒖刂屏鞒唐驮幊唐獙W(xué)習(xí)筆記的鏈接,打算入門Python的朋友們可以按需查看并交流。 第一部分:緒論篇 1、Python數(shù)據(jù)模型 第二部分:數(shù)據(jù)結(jié)構(gòu)篇 2、序列構(gòu)成...

    U2FsdGVkX1x 評論0 收藏0
  • 流暢的python

    摘要:流暢的中有很多奇技淫巧,整本書都在強調(diào)如何最大限度地利用標(biāo)準(zhǔn)庫。常見的扁平序列包括,,等。數(shù)組支持所有跟可變序列有關(guān)的操作,包括和。和用于指定列表的區(qū)間,默認(rèn)是使用整個列表。但是元組的賦值不被允許,當(dāng)異發(fā)生時 流暢的python中有很多奇技淫巧,整本書都在強調(diào)如何最大限度地利用Python 標(biāo)準(zhǔn)庫。介紹了很多python的不常用的數(shù)據(jù)類型、操作、庫等,對于入門python后想要提升對p...

    Alan 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<