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

資訊專欄INFORMATION COLUMN

python學(xué)習(xí)筆記-魔術(shù)方法,讓自定義類更像內(nèi)置類型

changfeng1050 / 2442人閱讀

摘要:的魔術(shù)方法是中那些預(yù)定義的像類型的函數(shù)。使用的魔術(shù)方法的最大優(yōu)勢在于提供了簡單的方法讓對象可以表現(xiàn)得像內(nèi)置類型一樣。廖雪峰老師教程里寫的是方法,不知道為啥。

Python的魔術(shù)方法是Python中那些預(yù)定義的像__XXX__類型的函數(shù)。
使用Python的魔術(shù)方法的最大優(yōu)勢在于python提供了簡單的方法讓對象可以表現(xiàn)得像內(nèi)置類型一樣。

__str__函數(shù)

__str__函數(shù)用于處理打印實例本身的時候的輸出內(nèi)容。如果沒有覆寫該函數(shù),則默認(rèn)輸出一個對象名稱和內(nèi)存地址。
例如:

>>> class Student(object):
...     def __init__(self,name):
...             self._name = name
...
>>> print Student()

輸出:<__main__.Student object at 0x0000000002A929E8>.
那么我們?nèi)绾巫屳敵龅慕Y(jié)果可讀性更高一點呢?我們可以覆寫__str__函數(shù)。例如

>>> class Student(object):
...     def __init__(self, name):
...             self._name = name
...     def __str__(self):
...             return  "I"m a student, named %s" % self._name
...
>>> print Student("Charlie")

輸出結(jié)果就是:I"m a student, named Charlie.
我們將str()函數(shù)作用于該對象的時候,其實是調(diào)用了該對象的__str__函數(shù)。

_repr_ 函數(shù)

__repr__也是將對象序列化,但是__repr__更多的是給python編譯器看的。__str__更多的是可讀性(readable)。
我們將repr()函數(shù)作用于摸某一個對象的時候,調(diào)用的其實就是該函數(shù)的__repr__函數(shù)。

repr()成對的是eval()函數(shù)。eval()函數(shù)是將序列化后的對象重新轉(zhuǎn)為對象。前提是該對象實現(xiàn)了__repr__函數(shù)。

上面這一段話基于自己的理解,不知道對錯。

>>> item = [1,2,3]
>>> repr(item)
"[1, 2, 3]"
>>> other_item = eval(repr(item))
>>> other_item[1]
2
__iter__函數(shù)

我們經(jīng)常對list或者tuple使用for...in...來迭代。那是list繼承自Iterable。Iterable實現(xiàn)了__iter__函數(shù)。

要想將一個自定義的對象變成一個可迭代的對象,那么必須要實現(xiàn)兩個方法:__iter__next.

__iter__函數(shù)返回一個對象。迭代的時候則會不斷地調(diào)用next函數(shù)拿到下一個值,直到捕獲到StopIteration停止。
廖雪峰老師教程里寫的是__next__方法,不知道為啥。

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    def __iter__(self):
        return self

    def next(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 10000:
            raise StopIteration
        return self.a


for i in Fib():
    print i
__getitem__函數(shù)

上面通過實現(xiàn)__iter__函數(shù)實現(xiàn)對象的迭代。
那么如何實現(xiàn)對象按下標(biāo)取出元素呢。
這是通過實現(xiàn)對象的__getitem__方法。
我們來舉一個?子。我們新建了一個類MyList,我們要辦它實現(xiàn)普通list的一些功能,比如(1)根據(jù)下標(biāo)獲取值;(2)正數(shù)順序單步長切片 (3)任意步長切片

class MyList(object):
    def __init__(self, *args):
        self.numbers = args

    def __getitem__(self, item):
        return self.numbers[item]


my_list = MyList(1, 2, 3, 4, 6, 5, 3)
print my_list[2]

當(dāng)然,上面實現(xiàn)了根據(jù)下標(biāo)獲取值。但是這還不夠。我們還需要實現(xiàn)切片功能。例如my_list[1:3].
我們對對象進(jìn)行切片操作的時候,調(diào)用的氣勢也是__getitem__函數(shù)。此時,該函數(shù)獲取到的并不是int對象,而是slice對象。
例如下面的代碼

class MyList(object):
    def __init__(self, *args):
        self.numbers = args

    def __getitem__(self, item):
        if isinstance(item, int):
            return self.numbers[item]
        elif isinstance(item, slice):
            # 寫習(xí)慣了其他語言,差點忘記了三元運算符的格式了,吼吼吼。
            # 下面句三元運算符的意思是,若為空,則為切片從0開始。
            start = item.start if item.start is not None else 0
            # 下面句三元運算符的意思是,若為空,則為切片到最末端結(jié)束。
            stop = item.stop if item.stop is not None else len(self.numbers)
            return self.numbers[start:stop]


my_list = MyList(1, 2, 3, 4, 6, 5, 3)
print my_list[2:5]

上面的代碼終于實現(xiàn)了切片功能,但是還沒考慮負(fù)數(shù)呢。那么我們加一把勁再來改一下。代碼如下:

class MyList(object):
    def __init__(self, *args):
        self.numbers = args

    def __getitem__(self, item):
        if isinstance(item, int):
            return self.numbers[item]
        elif isinstance(item, slice):
            start = item.start if item.start is not None else 0
            stop = item.stop if item.stop is not None else len(self.numbers)

            length = len(self.numbers)
            start = length + start + 1 if start < 0 else start
            stop = length + stop + 1 if stop < 0 else stop
            return self.numbers[start:stop]

my_list = MyList(1, 2, 3, 4, 6, 5, 3)
print my_list[1:-1]

哇塞,寫完了,棒棒棒

_getattar_

在調(diào)用某一個對象不存在的屬性或者方法的時候,會拋出一個一個AttributeError錯誤。
但是如果我們實現(xiàn)了類中的魔術(shù)方法__getattar__,那么在調(diào)用不存在的屬性或者方法的時候,就會調(diào)用該魔術(shù)方法。

class Apple(object):
    def __getattr__(self, item):
        if item == "attar1":
            return "print"
        if item == "method1":
            return lambda x: "hello %s" % x


apple = Apple()
print apple.attar1
print apple.method1

__getattar__函數(shù)一個重要的適用場景就是實現(xiàn)鏈?zhǔn)秸{(diào)用。例如我們在調(diào)用某一個api的時候:

GET users/articles/index

那么我們就希望我們的代碼可以實現(xiàn)`Api.users.articles.index這么調(diào)用。
思考一下,要實現(xiàn)鏈?zhǔn)秸{(diào)用,最重要的就是每一個調(diào)用都是返回一個實例~~。

# coding=utf-8
class Api(object):
    def __init__(self, path=""):
        self._path = path

    def __getattr__(self, name):
        return Api("%s/%s" % (self._path, name))

    # 定義一個Post方法來發(fā)送請求
    def post(self):
        print self._path


api = Api()
api.user.articles.index.post()

廖雪峰在他的教程中給我們出了一個題目:
例如調(diào)用github的api:users/:user/repos一樣,中間的user名需要動態(tài)替換。
我們希望能api.users("charlie").repos這么調(diào)用。那么代碼該如何實現(xiàn)呢?這可能需要用到另一個方法__call__

_call_ 函數(shù)

一個對象既有屬性,又有方法。我們在調(diào)用一個實例的方法的時候,我們可以使用instance.method()的形式調(diào)用。
其實也可以將實例本身看成一個函數(shù)用來調(diào)用,我們需要做的就是實現(xiàn)__call__函數(shù)本身。

class Apple(object):
    def __call__(self, *args, **kwargs):
        return args


apple = Apple()
print apple("yes", "no")

此時我們再來看一下上面提到的實現(xiàn)api.users("charlie").repos鏈?zhǔn)秸{(diào)用的方法。

# coding=utf-8
class Api(object):
    def __init__(self, path=""):
        self._path = path

    def __getattr__(self, name):
        return Api("%s/%s" % (self._path, name))

    def __call__(self, args):
        self._path = "%s/%s" % (self._path, args)
        return Api(self._path)

    # 定義一個Post方法來發(fā)送請求
    def post(self):
        print self._path


api = Api()
api.users("Charlie").index.post()

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

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

相關(guān)文章

  • 聊聊技術(shù)寫作的個人體會

    摘要:由此看來,的官方文檔就把當(dāng)成內(nèi)置函數(shù),這個認(rèn)識錯誤是有根源的等到的時候,官方把錯誤改正過來了,然而改得并不徹底。使用進(jìn)行判斷,結(jié)果為的才是內(nèi)置函數(shù)。 showImg(https://segmentfault.com/img/bVbm3Bu?w=5184&h=3456);有群友問過,是什么原因使我開始寫技術(shù)公眾號,又是什么動力讓我堅持寫的。 在我看來,寫作是一件不能敷衍的事,通過寫作來學(xué)...

    madthumb 評論0 收藏0
  • Python學(xué)習(xí)之路28-符合Python風(fēng)格的對象

    摘要:本篇繼續(xù)學(xué)習(xí)之路,實現(xiàn)更多的特殊方法以讓自定義類的行為跟真正的對象一樣。之所以要讓向量不可變,是因為我們在計算向量的哈希值時需要用到和的哈希值,如果這兩個值可變,那向量的哈希值就能隨時變化,這將不是一個可散列的對象。 《流暢的Python》筆記。本篇是面向?qū)ο髴T用方法的第二篇。前一篇講的是內(nèi)置對象的結(jié)構(gòu)和行為,本篇則是自定義對象。本篇繼續(xù)Python學(xué)習(xí)之路20,實現(xiàn)更多的特殊方法以讓...

    Eric 評論0 收藏0
  • es6學(xué)習(xí)筆記-Symbol_v1.0_byKL

    摘要:它是語言的第七種數(shù)據(jù)類型前六種是布爾值字符串?dāng)?shù)值對象。為了防止沖突這就是引入的原因。指向了這個內(nèi)部方法調(diào)用了返回對象的屬性等于一個布爾值,表示該對象使用時,是否可以展開。數(shù)組的默認(rèn)行為是可以展開返回對象的屬性,指向當(dāng)前對象的構(gòu)造函數(shù)。 es6學(xué)習(xí)筆記-Symbol_v1.0 基本抄了一次內(nèi)容,有很多只是知道其然并不知其所以然,不過也算是加深了一次印象,另外每段代碼我都有手動執(zhí)行過. E...

    Lowky 評論0 收藏0

發(fā)表評論

0條評論

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