摘要:的魔術方法是中那些預定義的像類型的函數。使用的魔術方法的最大優勢在于提供了簡單的方法讓對象可以表現得像內置類型一樣。廖雪峰老師教程里寫的是方法,不知道為啥。
Python的魔術方法是Python中那些預定義的像__XXX__類型的函數。
使用Python的魔術方法的最大優勢在于python提供了簡單的方法讓對象可以表現得像內置類型一樣。
__str__函數用于處理打印實例本身的時候的輸出內容。如果沒有覆寫該函數,則默認輸出一個對象名稱和內存地址。
例如:
>>> class Student(object): ... def __init__(self,name): ... self._name = name ... >>> print Student()
輸出:<__main__.Student object at 0x0000000002A929E8>.
那么我們如何讓輸出的結果可讀性更高一點呢?我們可以覆寫__str__函數。例如
>>> 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")
輸出結果就是:I"m a student, named Charlie.
我們將str()函數作用于該對象的時候,其實是調用了該對象的__str__函數。
__repr__也是將對象序列化,但是__repr__更多的是給python編譯器看的。__str__更多的是可讀性(readable)。
我們將repr()函數作用于摸某一個對象的時候,調用的其實就是該函數的__repr__函數。
與repr()成對的是eval()函數。eval()函數是將序列化后的對象重新轉為對象。前提是該對象實現了__repr__函數。
上面這一段話基于自己的理解,不知道對錯。
>>> item = [1,2,3] >>> repr(item) "[1, 2, 3]" >>> other_item = eval(repr(item)) >>> other_item[1] 2__iter__函數
我們經常對list或者tuple使用for...in...來迭代。那是list繼承自Iterable。Iterable實現了__iter__函數。
要想將一個自定義的對象變成一個可迭代的對象,那么必須要實現兩個方法:__iter__和next.
__iter__函數返回一個對象。迭代的時候則會不斷地調用next函數拿到下一個值,直到捕獲到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__函數
上面通過實現__iter__函數實現對象的迭代。
那么如何實現對象按下標取出元素呢。
這是通過實現對象的__getitem__方法。
我們來舉一個?子。我們新建了一個類MyList,我們要辦它實現普通list的一些功能,比如(1)根據下標獲取值;(2)正數順序單步長切片 (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]
當然,上面實現了根據下標獲取值。但是這還不夠。我們還需要實現切片功能。例如my_list[1:3].
我們對對象進行切片操作的時候,調用的氣勢也是__getitem__函數。此時,該函數獲取到的并不是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): # 寫習慣了其他語言,差點忘記了三元運算符的格式了,吼吼吼。 # 下面句三元運算符的意思是,若為空,則為切片從0開始。 start = item.start if item.start is not None else 0 # 下面句三元運算符的意思是,若為空,則為切片到最末端結束。 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]
上面的代碼終于實現了切片功能,但是還沒考慮負數呢。那么我們加一把勁再來改一下。代碼如下:
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_在調用某一個對象不存在的屬性或者方法的時候,會拋出一個一個AttributeError錯誤。
但是如果我們實現了類中的魔術方法__getattar__,那么在調用不存在的屬性或者方法的時候,就會調用該魔術方法。
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__函數一個重要的適用場景就是實現鏈式調用。例如我們在調用某一個api的時候:
GET users/articles/index
那么我們就希望我們的代碼可以實現`Api.users.articles.index這么調用。
思考一下,要實現鏈式調用,最重要的就是每一個調用都是返回一個實例~~。
# 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方法來發送請求 def post(self): print self._path api = Api() api.user.articles.index.post()
廖雪峰在他的教程中給我們出了一個題目:
例如調用github的api:users/:user/repos一樣,中間的user名需要動態替換。
我們希望能api.users("charlie").repos這么調用。那么代碼該如何實現呢?這可能需要用到另一個方法__call__
一個對象既有屬性,又有方法。我們在調用一個實例的方法的時候,我們可以使用instance.method()的形式調用。
其實也可以將實例本身看成一個函數用來調用,我們需要做的就是實現__call__函數本身。
class Apple(object): def __call__(self, *args, **kwargs): return args apple = Apple() print apple("yes", "no")
此時我們再來看一下上面提到的實現api.users("charlie").repos鏈式調用的方法。
# 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方法來發送請求 def post(self): print self._path api = Api() api.users("Charlie").index.post()
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/38334.html
摘要:由此看來,的官方文檔就把當成內置函數,這個認識錯誤是有根源的等到的時候,官方把錯誤改正過來了,然而改得并不徹底。使用進行判斷,結果為的才是內置函數。 showImg(https://segmentfault.com/img/bVbm3Bu?w=5184&h=3456);有群友問過,是什么原因使我開始寫技術公眾號,又是什么動力讓我堅持寫的。 在我看來,寫作是一件不能敷衍的事,通過寫作來學...
摘要:本篇繼續學習之路,實現更多的特殊方法以讓自定義類的行為跟真正的對象一樣。之所以要讓向量不可變,是因為我們在計算向量的哈希值時需要用到和的哈希值,如果這兩個值可變,那向量的哈希值就能隨時變化,這將不是一個可散列的對象。 《流暢的Python》筆記。本篇是面向對象慣用方法的第二篇。前一篇講的是內置對象的結構和行為,本篇則是自定義對象。本篇繼續Python學習之路20,實現更多的特殊方法以讓...
摘要:它是語言的第七種數據類型前六種是布爾值字符串數值對象。為了防止沖突這就是引入的原因。指向了這個內部方法調用了返回對象的屬性等于一個布爾值,表示該對象使用時,是否可以展開。數組的默認行為是可以展開返回對象的屬性,指向當前對象的構造函數。 es6學習筆記-Symbol_v1.0 基本抄了一次內容,有很多只是知道其然并不知其所以然,不過也算是加深了一次印象,另外每段代碼我都有手動執行過. E...
閱讀 2170·2021-11-25 09:43
閱讀 2249·2021-11-24 09:39
閱讀 1540·2021-11-22 12:02
閱讀 2984·2021-11-17 09:33
閱讀 3408·2021-11-15 11:38
閱讀 2718·2021-10-13 09:40
閱讀 1065·2021-09-22 15:41
閱讀 1687·2019-08-30 10:58